Improve plugin caching
Summary: Extend the plasmoid startup cache to DataEngines and ContaimentActions. Include a cache for script engines. In practice it's always the same, we don't need to check the file system every time. Reviewers: #plasma, davidedmundson, mart Reviewed By: #plasma, davidedmundson, mart Subscribers: davidedmundson, mart, broulik, kde-frameworks-devel Tags: #frameworks Differential Revision: https://phabricator.kde.org/D22258
This commit is contained in:
parent
6d53dfad57
commit
21227e0f98
@ -69,15 +69,23 @@ public:
|
||||
static QString s_servicesPluginDir;
|
||||
static QString s_containmentActionsPluginDir;
|
||||
|
||||
// We only use this cache during start of the process to speed up many consecutive calls
|
||||
// After that, we're too afraid to produce race conditions and it's not that time-critical anyway
|
||||
// the 20 seconds here means that the cache is only used within 20sec during startup, after that,
|
||||
// complexity goes up and we'd have to update the cache in order to avoid subtle bugs
|
||||
// just not using the cache is way easier then, since it doesn't make *that* much of a difference,
|
||||
// anyway
|
||||
int maxCacheAge = 20;
|
||||
qint64 pluginCacheAge = 0;
|
||||
QHash<QString, QVector<KPluginMetaData>> pluginCache;
|
||||
class Cache {
|
||||
// We only use this cache during start of the process to speed up many consecutive calls
|
||||
// After that, we're too afraid to produce race conditions and it's not that time-critical anyway
|
||||
// the 20 seconds here means that the cache is only used within 20sec during startup, after that,
|
||||
// complexity goes up and we'd have to update the cache in order to avoid subtle bugs
|
||||
// just not using the cache is way easier then, since it doesn't make *that* much of a difference,
|
||||
// anyway
|
||||
int maxCacheAge = 20;
|
||||
qint64 pluginCacheAge = 0;
|
||||
QHash<QString, QVector<KPluginMetaData>> plugins;
|
||||
|
||||
public:
|
||||
QVector<KPluginMetaData> findPluginsById(const QString& name, const QStringList &dirs);
|
||||
};
|
||||
Cache plasmoidCache;
|
||||
Cache dataengineCache;
|
||||
Cache containmentactionCache;
|
||||
};
|
||||
|
||||
QSet<QString> PluginLoaderPrivate::s_customCategories;
|
||||
@ -171,49 +179,8 @@ Applet *PluginLoader::loadApplet(const QString &name, uint appletId, const QVari
|
||||
appletId = ++AppletPrivate::s_maxAppletId;
|
||||
}
|
||||
|
||||
const qint64 now = qRound64(QDateTime::currentMSecsSinceEpoch() / 1000.0);
|
||||
bool useRuntimeCache = true;
|
||||
if (now - d->pluginCacheAge > d->maxCacheAge && d->pluginCacheAge != 0) {
|
||||
// cache is old and we're not within a few seconds of startup anymore
|
||||
useRuntimeCache = false;
|
||||
d->pluginCache.clear();
|
||||
}
|
||||
|
||||
if (d->pluginCacheAge == 0) {
|
||||
// Find all the plugins now, but only once
|
||||
d->pluginCacheAge = now;
|
||||
|
||||
auto insertIntoCache = [this](const QString &pluginPath) {
|
||||
KPluginMetaData metadata(pluginPath);
|
||||
if (!metadata.isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
d->pluginCache[metadata.pluginId()].append(metadata);
|
||||
};
|
||||
|
||||
KPluginLoader::forEachPlugin(PluginLoaderPrivate::s_plasmoidsPluginDir, insertIntoCache);
|
||||
// COMPAT CODE for applets installed into the toplevel plugins dir by mistake.
|
||||
KPluginLoader::forEachPlugin(QString(), insertIntoCache);
|
||||
}
|
||||
|
||||
//if name wasn't a path, pluginName == name
|
||||
const QString pluginName = name.section(QLatin1Char('/'), -1);
|
||||
|
||||
QVector<KPluginMetaData> plugins;
|
||||
|
||||
if (useRuntimeCache) {
|
||||
auto it = d->pluginCache.constFind(pluginName);
|
||||
if (it != d->pluginCache.constEnd()) {
|
||||
plugins = *it;
|
||||
}
|
||||
} else {
|
||||
plugins = KPluginLoader::findPluginsById(PluginLoaderPrivate::s_plasmoidsPluginDir, pluginName);
|
||||
// COMPAT CODE for applets installed into the toplevel plugins dir by mistake.
|
||||
if (plugins.isEmpty()) {
|
||||
plugins = KPluginLoader::findPluginsById(QString(), pluginName);
|
||||
}
|
||||
}
|
||||
// Need to pass the empty directory because it's where plasmoids used to be
|
||||
const auto plugins = d->plasmoidCache.findPluginsById(name, { PluginLoaderPrivate::s_plasmoidsPluginDir, {} });
|
||||
|
||||
const KPackage::Package p = KPackage::PackageLoader::self()->loadPackage(QStringLiteral("Plasma/Applet"), name);
|
||||
|
||||
@ -263,19 +230,12 @@ DataEngine *PluginLoader::loadDataEngine(const QString &name)
|
||||
}
|
||||
|
||||
// Look for C++ plugins first
|
||||
auto filter = [&name](const KPluginMetaData &md) -> bool
|
||||
{
|
||||
return md.pluginId() == name;
|
||||
};
|
||||
QVector<KPluginMetaData> plugins = KPluginLoader::findPlugins(PluginLoaderPrivate::s_dataEnginePluginDir, filter);
|
||||
|
||||
const QVector<KPluginMetaData> plugins = d->dataengineCache.findPluginsById(name, {PluginLoaderPrivate::s_dataEnginePluginDir});
|
||||
if (!plugins.isEmpty()) {
|
||||
KPluginLoader loader(plugins.first().fileName());
|
||||
KPluginLoader loader(plugins.constFirst().fileName());
|
||||
const QVariantList argsWithMetaData = QVariantList() << loader.metaData().toVariantMap();
|
||||
KPluginFactory *factory = loader.factory();
|
||||
if (factory) {
|
||||
engine = factory->create<Plasma::DataEngine>(nullptr, argsWithMetaData);
|
||||
}
|
||||
return factory ? factory->create<Plasma::DataEngine>(nullptr, argsWithMetaData) : nullptr;
|
||||
}
|
||||
if (engine) {
|
||||
return engine;
|
||||
@ -406,13 +366,7 @@ ContainmentActions *PluginLoader::loadContainmentActions(Containment *parent, co
|
||||
return actions;
|
||||
}
|
||||
|
||||
|
||||
// Look for C++ plugins first
|
||||
auto filter = [&name](const KPluginMetaData &md) -> bool
|
||||
{
|
||||
return md.pluginId() == name;
|
||||
};
|
||||
QVector<KPluginMetaData> plugins = KPluginLoader::findPlugins(PluginLoaderPrivate::s_containmentActionsPluginDir, filter);
|
||||
const QVector<KPluginMetaData> plugins = d->containmentactionCache.findPluginsById(name, {PluginLoaderPrivate::s_containmentActionsPluginDir});
|
||||
|
||||
if (!plugins.isEmpty()) {
|
||||
KPluginLoader loader(plugins.first().fileName());
|
||||
@ -891,5 +845,53 @@ bool PluginLoader::isPluginVersionCompatible(KPluginLoader &loader)
|
||||
return true;
|
||||
}
|
||||
|
||||
} // Plasma Namespace
|
||||
QVector<KPluginMetaData> PluginLoaderPrivate::Cache::findPluginsById(const QString& name, const QStringList &dirs)
|
||||
{
|
||||
const qint64 now = qRound64(QDateTime::currentMSecsSinceEpoch() / 1000.0);
|
||||
bool useRuntimeCache = true;
|
||||
|
||||
if (pluginCacheAge == 0) {
|
||||
// Find all the plugins now, but only once
|
||||
pluginCacheAge = now;
|
||||
|
||||
auto insertIntoCache = [this](const QString &pluginPath) {
|
||||
KPluginMetaData metadata(pluginPath);
|
||||
if (!metadata.isValid()) {
|
||||
qWarning() << "invalid metadata" << pluginPath;
|
||||
return;
|
||||
}
|
||||
|
||||
plugins[metadata.pluginId()].append(metadata);
|
||||
};
|
||||
|
||||
for (const QString &dir : dirs)
|
||||
KPluginLoader::forEachPlugin(dir, insertIntoCache);
|
||||
} else if (now - pluginCacheAge > maxCacheAge) {
|
||||
// cache is old and we're not within a few seconds of startup anymore
|
||||
useRuntimeCache = false;
|
||||
plugins.clear();
|
||||
}
|
||||
|
||||
//if name wasn't a path, pluginName == name
|
||||
const QString pluginName = name.section(QLatin1Char('/'), -1);
|
||||
|
||||
QVector<KPluginMetaData> ret;
|
||||
|
||||
if (useRuntimeCache) {
|
||||
auto it = plugins.constFind(pluginName);
|
||||
if (it != plugins.constEnd()) {
|
||||
ret = *it;
|
||||
}
|
||||
qCDebug(LOG_PLASMA) << "loading applet by name" << name << useRuntimeCache << ret.size();
|
||||
} else {
|
||||
|
||||
for (const auto& dir : dirs) {
|
||||
ret = KPluginLoader::findPluginsById(dir, pluginName);
|
||||
if (!ret.isEmpty())
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // Plasma Namespace
|
||||
|
@ -20,7 +20,7 @@
|
||||
#include "scripting/scriptengine.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <kservice.h>
|
||||
#include <QGlobalStatic>
|
||||
|
||||
#include "applet.h"
|
||||
#include "dataengine.h"
|
||||
@ -32,6 +32,23 @@
|
||||
namespace Plasma
|
||||
{
|
||||
|
||||
static QVector<KPluginMetaData> listEngines(Types::ComponentTypes types, std::function<bool(const KPluginMetaData &)> filter)
|
||||
{
|
||||
QVector<KPluginMetaData> ret;
|
||||
const QVector<KPluginMetaData> plugins = KPluginLoader::findPlugins(QStringLiteral("plasma/scriptengines"));
|
||||
ret.reserve(plugins.size());
|
||||
for (const auto &plugin : plugins) {
|
||||
if (!filter(plugin))
|
||||
continue;
|
||||
const QStringList componentTypes = KPluginMetaData::readStringList(plugins.first().rawData(), QStringLiteral("X-Plasma-ComponentTypes"));
|
||||
if (((types & Types::AppletComponent) && componentTypes.contains(QStringLiteral("Applet")))
|
||||
||((types & Types::DataEngineComponent) && componentTypes.contains(QStringLiteral("DataEngine")))) {
|
||||
ret << plugin;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
ScriptEngine::ScriptEngine(QObject *parent)
|
||||
: QObject(parent),
|
||||
d(nullptr)
|
||||
@ -61,44 +78,42 @@ QString ScriptEngine::mainScript() const
|
||||
QStringList knownLanguages(Types::ComponentTypes types)
|
||||
{
|
||||
QStringList languages;
|
||||
const QVector<KPluginMetaData> plugins = KPluginLoader::findPlugins(QStringLiteral("plasma/scriptengines"));
|
||||
const QVector<KPluginMetaData> plugins = listEngines(types, [] (const KPluginMetaData &) -> bool { return true;});
|
||||
|
||||
foreach (const auto &plugin, plugins) {
|
||||
const QStringList componentTypes = KPluginMetaData::readStringList(plugins.first().rawData(), QStringLiteral("X-Plasma-ComponentTypes"));
|
||||
if (((types & Types::AppletComponent) && componentTypes.contains(QStringLiteral("Applet")))
|
||||
||((types & Types::DataEngineComponent) && componentTypes.contains(QStringLiteral("DataEngine")))) {
|
||||
languages << plugin.value(QStringLiteral("X-Plasma-API"));
|
||||
}
|
||||
}
|
||||
for (const auto &plugin : plugins)
|
||||
languages << plugin.value(QStringLiteral("X-Plasma-API"));
|
||||
|
||||
return languages;
|
||||
}
|
||||
|
||||
typedef QHash<QString, QSharedPointer<KPluginLoader>> EngineCache;
|
||||
Q_GLOBAL_STATIC(EngineCache, engines)
|
||||
|
||||
ScriptEngine *loadEngine(const QString &language, Types::ComponentType type, QObject *parent,
|
||||
const QVariantList &args = QVariantList())
|
||||
{
|
||||
Q_UNUSED(parent);
|
||||
|
||||
ScriptEngine *engine = nullptr;
|
||||
{
|
||||
auto it = engines->constFind(language);
|
||||
if (it != engines->constEnd()) {
|
||||
return (*it)->factory()->create<Plasma::ScriptEngine>(nullptr, args);
|
||||
}
|
||||
}
|
||||
|
||||
ScriptEngine *engine = nullptr;
|
||||
auto filter = [&language](const KPluginMetaData &md) -> bool
|
||||
{
|
||||
return md.value(QStringLiteral("X-Plasma-API")) == language;
|
||||
};
|
||||
QVector<KPluginMetaData> plugins = KPluginLoader::findPlugins(QStringLiteral("plasma/scriptengines"), filter);
|
||||
|
||||
const QVector<KPluginMetaData> plugins = listEngines(type, filter);
|
||||
if (!plugins.isEmpty()) {
|
||||
const QStringList componentTypes = KPluginMetaData::readStringList(plugins.first().rawData(), QStringLiteral("X-Plasma-ComponentTypes"));
|
||||
if (((type & Types::AppletComponent) && !componentTypes.contains(QStringLiteral("Applet")))
|
||||
|| ((type & Types::DataEngineComponent) && !componentTypes.contains(QStringLiteral("DataEngine")))) {
|
||||
|
||||
qCWarning(LOG_PLASMA) << "ScriptEngine" << plugins.first().name() << "does not provide Applet or DataEngine components, returning empty.";
|
||||
return nullptr;
|
||||
}
|
||||
KPluginLoader loader(plugins.first().fileName());
|
||||
KPluginFactory *factory = loader.factory();
|
||||
QSharedPointer<KPluginLoader> loader(new KPluginLoader(plugins.first().fileName()));
|
||||
KPluginFactory *factory = loader->factory();
|
||||
if (factory) {
|
||||
engine = factory->create<Plasma::ScriptEngine>(nullptr, args);
|
||||
engines->insert(language, loader);
|
||||
} else {
|
||||
qCWarning(LOG_PLASMA) << "Unable to load" << plugins.first().name() << "ScriptEngine";
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user