Delay modifications to MIME database until first use

Initialization of the MIME database takes time, and it is good to avoid
this during startup.
We nevertheless want to apply some modifications to the MIME database, so
we need to delay these modifications until first use. Allow registration
of additional initialization functions. Since the initialization
functions access the MIME database, which does locking for thread-
safety, we need to separate the initialization to outside these locking
functions.

Change-Id: I2b1706347768bcf081644e078ccfa45302d61641
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
Eike Ziller
2023-09-05 10:10:44 +02:00
parent 7200644f75
commit 1870501443
9 changed files with 88 additions and 41 deletions

View File

@@ -957,6 +957,7 @@ void PluginManagerPrivate::nextDelayedInitialize()
break; // do next delayedInitialize after a delay
}
if (delayedInitializeQueue.empty()) {
Utils::setMimeStartupPhase(MimeStartupPhase::UpAndRunning);
m_isInitializationDone = true;
delete delayedInitializeTimer;
delayedInitializeTimer = nullptr;
@@ -1370,7 +1371,6 @@ void PluginManagerPrivate::loadPlugins()
loadPlugin(spec, PluginSpec::Initialized);
}
Utils::setMimeStartupPhase(MimeStartupPhase::PluginsDelayedInitializing);
{
NANOTRACE_SCOPE("ExtensionSystem", "ExtensionsInitialized");
Utils::reverseForeach(queue, [this](PluginSpec *spec) {
@@ -1384,8 +1384,8 @@ void PluginManagerPrivate::loadPlugins()
});
}
emit q->pluginsChanged();
Utils::setMimeStartupPhase(MimeStartupPhase::UpAndRunning);
Utils::setMimeStartupPhase(MimeStartupPhase::PluginsDelayedInitializing);
delayedInitializeTimer = new QTimer;
delayedInitializeTimer->setInterval(DELAYED_INITIALIZE_INTERVAL);
delayedInitializeTimer->setSingleShot(true);

View File

@@ -562,12 +562,9 @@ MimeDatabase::~MimeDatabase()
*/
MimeType MimeDatabase::mimeTypeForName(const QString &nameOrAlias) const
{
d->checkInitPhase(nameOrAlias);
QMutexLocker locker(&d->mutex);
if (d->m_startupPhase <= int(MimeStartupPhase::PluginsInitializing))
qWarning("Accessing MimeDatabase for %s before plugins are initialized",
qPrintable(nameOrAlias));
return d->mimeTypeForName(nameOrAlias);
}
@@ -601,12 +598,9 @@ MimeType MimeDatabase::mimeTypeForName(const QString &nameOrAlias) const
*/
MimeType MimeDatabase::mimeTypeForFile(const QFileInfo &fileInfo, MatchMode mode) const
{
d->checkInitPhase(fileInfo.filePath());
QMutexLocker locker(&d->mutex);
if (d->m_startupPhase <= int(MimeStartupPhase::PluginsInitializing))
qWarning("Accessing MimeDatabase for %s before plugins are initialized",
qPrintable(fileInfo.filePath()));
if (fileInfo.isDir())
return d->mimeTypeForName(QLatin1String("inode/directory"));
@@ -659,12 +653,9 @@ MimeType MimeDatabase::mimeTypeForFile(const QFileInfo &fileInfo, MatchMode mode
MimeType MimeDatabase::mimeTypeForFile(const QString &fileName, MatchMode mode) const
{
if (mode == MatchExtension) {
d->checkInitPhase(fileName);
QMutexLocker locker(&d->mutex);
if (d->m_startupPhase <= int(MimeStartupPhase::PluginsInitializing))
qWarning("Accessing MimeDatabase for %s before plugins are initialized",
qPrintable(fileName));
const QStringList matches = d->mimeTypeForFileName(fileName);
const int matchCount = matches.count();
if (matchCount == 0) {
@@ -696,12 +687,9 @@ MimeType MimeDatabase::mimeTypeForFile(const QString &fileName, MatchMode mode)
*/
QList<MimeType> MimeDatabase::mimeTypesForFileName(const QString &fileName) const
{
d->checkInitPhase(fileName);
QMutexLocker locker(&d->mutex);
if (d->m_startupPhase <= int(MimeStartupPhase::PluginsInitializing))
qWarning("Accessing MimeDatabase for %s before plugins are initialized",
qPrintable(fileName));
const QStringList matches = d->mimeTypeForFileName(fileName);
QList<MimeType> mimes;
mimes.reserve(matches.count());
@@ -731,11 +719,9 @@ QString MimeDatabase::suffixForFileName(const QString &fileName) const
*/
MimeType MimeDatabase::mimeTypeForData(const QByteArray &data) const
{
d->checkInitPhase("data");
QMutexLocker locker(&d->mutex);
if (d->m_startupPhase <= int(MimeStartupPhase::PluginsInitializing))
qWarning("Accessing MimeDatabase for data before plugins are initialized");
int accuracy = 0;
return d->findByData(data, &accuracy);
}
@@ -863,11 +849,9 @@ MimeType MimeDatabase::mimeTypeForFileNameAndData(const QString &fileName, const
*/
QList<MimeType> MimeDatabase::allMimeTypes() const
{
d->checkInitPhase("all mime types");
QMutexLocker locker(&d->mutex);
if (d->m_startupPhase <= int(MimeStartupPhase::PluginsInitializing))
qWarning("Accessing MimeDatabase for all mime types before plugins are initialized");
return d->allMimeTypes();
}
@@ -924,4 +908,27 @@ void MimeDatabasePrivate::setGlobPatternsForMimeType(const MimeType &mimeType,
}
}
void MimeDatabasePrivate::checkInitPhase(const QString &info)
{
QReadLocker locker(&m_initMutex);
if (m_startupPhase <= int(MimeStartupPhase::PluginsInitializing)) {
qWarning("Accessing MimeDatabase for %s before plugins are initialized", qPrintable(info));
return;
}
// run initialization functions and ensure providers are loaded
// the initializers will call other MIME database functions which "checkInitPhase" again,
// so make sure not to recurse
if (!m_initialized.exchange(true)) {
for (const std::function<void()> &f : m_initializers)
f();
QMutexLocker locker(&mutex);
providers();
}
}
void MimeDatabasePrivate::addInitializer(const std::function<void()> &init)
{
m_initializers.append(init);
}
} // namespace Utils

View File

@@ -25,8 +25,11 @@
#include <QtCore/qlist.h>
#include <QtCore/qmutex.h>
#include <vector>
#include <QReadWriteLock>
#include <atomic>
#include <memory>
#include <vector>
QT_BEGIN_NAMESPACE
class QIODevice;
@@ -75,6 +78,8 @@ public:
void setMagicRulesForMimeType(const MimeType &mimeType,
const QMap<int, QList<MimeMagicRule>> &rules);
void setGlobPatternsForMimeType(const MimeType &mimeType, const QStringList &patterns);
void checkInitPhase(const QString &info);
void addInitializer(const std::function<void()> &init);
private:
using Providers = std::vector<std::unique_ptr<MimeProviderBase>>;
@@ -86,6 +91,7 @@ private:
QElapsedTimer m_lastCheck;
// added for Qt Creator
QList<std::function<void()>> m_initializers;
QHash<QString, QByteArray> m_additionalData; // id -> data
bool m_forceLoad = true;
@@ -94,6 +100,8 @@ public:
QMutex mutex;
// added for Qt Creator
QReadWriteLock m_initMutex;
std::atomic_bool m_initialized = false;
int m_startupPhase = 0;
};

View File

@@ -57,7 +57,7 @@ QList<MimeType> allMimeTypes()
void setMimeStartupPhase(MimeStartupPhase phase)
{
auto d = MimeDatabasePrivate::instance();
QMutexLocker locker(&d->mutex);
QWriteLocker locker(&d->m_initMutex);
if (int(phase) != d->m_startupPhase + 1) {
qWarning("Unexpected jump in MimedDatabase lifetime from %d to %d",
d->m_startupPhase,
@@ -69,12 +69,14 @@ void setMimeStartupPhase(MimeStartupPhase phase)
void addMimeTypes(const QString &id, const QByteArray &data)
{
auto d = MimeDatabasePrivate::instance();
QMutexLocker locker(&d->mutex);
if (d->m_startupPhase >= int(MimeStartupPhase::PluginsDelayedInitializing)) {
qWarning("Adding items for ID \"%s\" to MimeDatabase after initialization time",
qPrintable(id));
{
QReadLocker locker(&d->m_initMutex);
if (d->m_startupPhase >= int(MimeStartupPhase::PluginsDelayedInitializing)) {
qWarning("Adding items for ID \"%s\" to MimeDatabase after initialization time",
qPrintable(id));
}
}
QMutexLocker locker(&d->mutex);
d->addMimeData(id, data);
}
@@ -130,4 +132,14 @@ void visitMimeParents(const MimeType &mimeType,
}
}
/*!
The \a init function will be executed once after the MIME database is first initialized.
It must be thread safe.
*/
void addMimeInitializer(const std::function<void()> &init)
{
auto d = MimeDatabasePrivate::instance();
d->addInitializer(init);
}
} // namespace Utils

View File

@@ -43,6 +43,7 @@ enum class MimeStartupPhase {
};
QTCREATOR_UTILS_EXPORT void setMimeStartupPhase(MimeStartupPhase);
QTCREATOR_UTILS_EXPORT void addMimeInitializer(const std::function<void()> &init);
QTCREATOR_UTILS_EXPORT void addMimeTypes(const QString &id, const QByteArray &data);
QTCREATOR_UTILS_EXPORT QMap<int, QList<MimeMagicRule>> magicRulesForMimeType(
const MimeType &mimeType); // priority -> rules

View File

@@ -746,19 +746,25 @@ MimeTypeSettingsPrivate::UserMimeTypeHash MimeTypeSettingsPrivate::readUserModif
return userMimeTypes;
}
void MimeTypeSettingsPrivate::applyUserModifiedMimeTypes(const UserMimeTypeHash &mimeTypes)
static void registerUserModifiedMimeTypes(const MimeTypeSettingsPrivate::UserMimeTypeHash &mimeTypes)
{
// register in mime data base, and remember for later
for (auto it = mimeTypes.constBegin(); it != mimeTypes.constEnd(); ++it) {
Utils::MimeType mt = Utils::mimeTypeForName(it.key());
if (!mt.isValid()) // loaded from settings
if (!mt.isValid())
continue;
m_userModifiedMimeTypes.insert(it.key(), it.value());
Utils::setGlobPatternsForMimeType(mt, it.value().globPatterns);
Utils::setMagicRulesForMimeType(mt, it.value().rules);
}
}
void MimeTypeSettingsPrivate::applyUserModifiedMimeTypes(const UserMimeTypeHash &mimeTypes)
{
// register in mime data base, and remember for later
for (auto it = mimeTypes.constBegin(); it != mimeTypes.constEnd(); ++it)
m_userModifiedMimeTypes.insert(it.key(), it.value());
registerUserModifiedMimeTypes(mimeTypes);
}
// MimeTypeSettingsPage
MimeTypeSettings::MimeTypeSettings()
@@ -792,8 +798,9 @@ QStringList MimeTypeSettings::keywords() const
void MimeTypeSettings::restoreSettings()
{
MimeTypeSettingsPrivate::UserMimeTypeHash mimetypes
= MimeTypeSettingsPrivate::readUserModifiedMimeTypes();
MimeTypeSettingsPrivate::applyUserModifiedMimeTypes(mimetypes);
= MimeTypeSettingsPrivate::readUserModifiedMimeTypes();
MimeTypeSettingsPrivate::m_userModifiedMimeTypes = mimetypes;
Utils::addMimeInitializer([mimetypes] { registerUserModifiedMimeTypes(mimetypes); });
}
QWidget *MimeEditorDelegate::createEditor(QWidget *parent,

View File

@@ -516,9 +516,7 @@ void CppEditorPlugin::initialize()
void CppEditorPlugin::extensionsInitialized()
{
d->m_fileSettings.fromSettings(ICore::settings());
if (!d->m_fileSettings.applySuffixesToMimeDB())
qWarning("Unable to apply cpp suffixes to mime database (cpp mime types not found).\n");
d->m_fileSettings.addMimeInitializer();
const auto fileNamesPanelFactory = new ProjectPanelFactory;
fileNamesPanelFactory->setPriority(99);
fileNamesPanelFactory->setDisplayName(Tr::tr("C++ File Naming"));

View File

@@ -93,7 +93,7 @@ void CppFileSettings::fromSettings(QSettings *s)
s->endGroup();
}
bool CppFileSettings::applySuffixesToMimeDB()
static bool applySuffixes(const QString &sourceSuffix, const QString &headerSuffix)
{
Utils::MimeType mt;
mt = Utils::mimeTypeForName(QLatin1String(Constants::CPP_SOURCE_MIMETYPE));
@@ -107,6 +107,19 @@ bool CppFileSettings::applySuffixesToMimeDB()
return true;
}
void CppFileSettings::addMimeInitializer() const
{
Utils::addMimeInitializer([sourceSuffix = sourceSuffix, headerSuffix = headerSuffix] {
if (!applySuffixes(sourceSuffix, headerSuffix))
qWarning("Unable to apply cpp suffixes to mime database (cpp mime types not found).\n");
});
}
bool CppFileSettings::applySuffixesToMimeDB()
{
return applySuffixes(sourceSuffix, headerSuffix);
}
bool CppFileSettings::equals(const CppFileSettings &rhs) const
{
return lowerCaseFiles == rhs.lowerCaseFiles

View File

@@ -38,6 +38,7 @@ public:
void toSettings(QSettings *) const;
void fromSettings(QSettings *);
void addMimeInitializer() const;
bool applySuffixesToMimeDB();
// Convenience to return a license template completely formatted.