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

View File

@@ -562,12 +562,9 @@ MimeDatabase::~MimeDatabase()
*/ */
MimeType MimeDatabase::mimeTypeForName(const QString &nameOrAlias) const MimeType MimeDatabase::mimeTypeForName(const QString &nameOrAlias) const
{ {
d->checkInitPhase(nameOrAlias);
QMutexLocker locker(&d->mutex); 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); return d->mimeTypeForName(nameOrAlias);
} }
@@ -601,12 +598,9 @@ MimeType MimeDatabase::mimeTypeForName(const QString &nameOrAlias) const
*/ */
MimeType MimeDatabase::mimeTypeForFile(const QFileInfo &fileInfo, MatchMode mode) const MimeType MimeDatabase::mimeTypeForFile(const QFileInfo &fileInfo, MatchMode mode) const
{ {
d->checkInitPhase(fileInfo.filePath());
QMutexLocker locker(&d->mutex); 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()) if (fileInfo.isDir())
return d->mimeTypeForName(QLatin1String("inode/directory")); 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 MimeType MimeDatabase::mimeTypeForFile(const QString &fileName, MatchMode mode) const
{ {
if (mode == MatchExtension) { if (mode == MatchExtension) {
d->checkInitPhase(fileName);
QMutexLocker locker(&d->mutex); 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 QStringList matches = d->mimeTypeForFileName(fileName);
const int matchCount = matches.count(); const int matchCount = matches.count();
if (matchCount == 0) { if (matchCount == 0) {
@@ -696,12 +687,9 @@ MimeType MimeDatabase::mimeTypeForFile(const QString &fileName, MatchMode mode)
*/ */
QList<MimeType> MimeDatabase::mimeTypesForFileName(const QString &fileName) const QList<MimeType> MimeDatabase::mimeTypesForFileName(const QString &fileName) const
{ {
d->checkInitPhase(fileName);
QMutexLocker locker(&d->mutex); 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 QStringList matches = d->mimeTypeForFileName(fileName);
QList<MimeType> mimes; QList<MimeType> mimes;
mimes.reserve(matches.count()); mimes.reserve(matches.count());
@@ -731,11 +719,9 @@ QString MimeDatabase::suffixForFileName(const QString &fileName) const
*/ */
MimeType MimeDatabase::mimeTypeForData(const QByteArray &data) const MimeType MimeDatabase::mimeTypeForData(const QByteArray &data) const
{ {
d->checkInitPhase("data");
QMutexLocker locker(&d->mutex); QMutexLocker locker(&d->mutex);
if (d->m_startupPhase <= int(MimeStartupPhase::PluginsInitializing))
qWarning("Accessing MimeDatabase for data before plugins are initialized");
int accuracy = 0; int accuracy = 0;
return d->findByData(data, &accuracy); return d->findByData(data, &accuracy);
} }
@@ -863,11 +849,9 @@ MimeType MimeDatabase::mimeTypeForFileNameAndData(const QString &fileName, const
*/ */
QList<MimeType> MimeDatabase::allMimeTypes() const QList<MimeType> MimeDatabase::allMimeTypes() const
{ {
d->checkInitPhase("all mime types");
QMutexLocker locker(&d->mutex); 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(); 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 } // namespace Utils

View File

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

View File

@@ -57,7 +57,7 @@ QList<MimeType> allMimeTypes()
void setMimeStartupPhase(MimeStartupPhase phase) void setMimeStartupPhase(MimeStartupPhase phase)
{ {
auto d = MimeDatabasePrivate::instance(); auto d = MimeDatabasePrivate::instance();
QMutexLocker locker(&d->mutex); QWriteLocker locker(&d->m_initMutex);
if (int(phase) != d->m_startupPhase + 1) { if (int(phase) != d->m_startupPhase + 1) {
qWarning("Unexpected jump in MimedDatabase lifetime from %d to %d", qWarning("Unexpected jump in MimedDatabase lifetime from %d to %d",
d->m_startupPhase, d->m_startupPhase,
@@ -69,12 +69,14 @@ void setMimeStartupPhase(MimeStartupPhase phase)
void addMimeTypes(const QString &id, const QByteArray &data) void addMimeTypes(const QString &id, const QByteArray &data)
{ {
auto d = MimeDatabasePrivate::instance(); auto d = MimeDatabasePrivate::instance();
QMutexLocker locker(&d->mutex); {
QReadLocker locker(&d->m_initMutex);
if (d->m_startupPhase >= int(MimeStartupPhase::PluginsDelayedInitializing)) { if (d->m_startupPhase >= int(MimeStartupPhase::PluginsDelayedInitializing)) {
qWarning("Adding items for ID \"%s\" to MimeDatabase after initialization time", qWarning("Adding items for ID \"%s\" to MimeDatabase after initialization time",
qPrintable(id)); qPrintable(id));
}
} }
QMutexLocker locker(&d->mutex);
d->addMimeData(id, data); 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 } // namespace Utils

View File

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

View File

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

View File

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

View File

@@ -93,7 +93,7 @@ void CppFileSettings::fromSettings(QSettings *s)
s->endGroup(); s->endGroup();
} }
bool CppFileSettings::applySuffixesToMimeDB() static bool applySuffixes(const QString &sourceSuffix, const QString &headerSuffix)
{ {
Utils::MimeType mt; Utils::MimeType mt;
mt = Utils::mimeTypeForName(QLatin1String(Constants::CPP_SOURCE_MIMETYPE)); mt = Utils::mimeTypeForName(QLatin1String(Constants::CPP_SOURCE_MIMETYPE));
@@ -107,6 +107,19 @@ bool CppFileSettings::applySuffixesToMimeDB()
return true; 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 bool CppFileSettings::equals(const CppFileSettings &rhs) const
{ {
return lowerCaseFiles == rhs.lowerCaseFiles return lowerCaseFiles == rhs.lowerCaseFiles

View File

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