Don't use QSettings to "cache" plugin information

The main rationale of the cache was to examine the plugin's build-key
before loading it. Now that the build-key has been removed, the cache
has lost its usefulness.

This is part of a larger push to not use QSettings for Qt specific
settings or caches.

See also:
http://lists.qt.nokia.com/pipermail/qt5-feedback/2011-August/000892.html
http://lists.qt.nokia.com/pipermail/qt5-feedback/2011-August/000960.html
http://lists.qt.nokia.com/pipermail/qt5-feedback/2011-August/000907.html
http://lists.qt.nokia.com/pipermail/qt5-feedback/2011-August/000904.html

Change-Id: I96e84aa25983c8e06e027ff70cef109444c362a2
Reviewed-on: http://codereview.qt.nokia.com/3978
Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com>
Reviewed-by: Lars Knoll <lars.knoll@nokia.com>
This commit is contained in:
Bradley T. Hughes 2011-08-31 15:17:30 +02:00 committed by Qt by Nokia
parent 6fd75df288
commit 8ed47d961d
6 changed files with 77 additions and 177 deletions

View File

@ -266,18 +266,6 @@ bool QCoreApplicationPrivate::is_app_closing = false;
// initialized in qcoreapplication and in qtextstream autotest when setlocale is called.
Q_CORE_EXPORT bool qt_locale_initialized = false;
/*
Create an instance of Trolltech.conf. This ensures that the settings will not
be thrown out of QSetting's cache for unused settings.
*/
Q_GLOBAL_STATIC_WITH_ARGS(QSettings, staticTrolltechConf, (QSettings::UserScope, QLatin1String("Trolltech")))
QSettings *QCoreApplicationPrivate::trolltechConf()
{
return staticTrolltechConf();
}
Q_CORE_EXPORT uint qGlobalPostedEventsCount()
{
QThreadData *currentThreadData = QThreadData::current();

View File

@ -139,7 +139,6 @@ public:
static uint attribs;
static inline bool testAttribute(uint flag) { return attribs & (1 << flag); }
static int app_compile_version;
static QSettings *trolltechConf();
};
QT_END_NAMESPACE

View File

@ -45,7 +45,6 @@
#include "qfactoryinterface.h"
#include "qmap.h"
#include <qdir.h>
#include <qsettings.h>
#include <qdebug.h>
#include "qmutex.h"
#include "qplugin.h"
@ -107,7 +106,6 @@ void QFactoryLoader::update()
#ifdef QT_SHARED
Q_D(QFactoryLoader);
QStringList paths = QCoreApplication::libraryPaths();
QSettings settings(QSettings::UserScope, QLatin1String("Trolltech"));
for (int i = 0; i < paths.count(); ++i) {
const QString &pluginDir = paths.at(i);
// Already loaded, skip it...
@ -127,7 +125,7 @@ void QFactoryLoader::update()
qDebug() << "QFactoryLoader::QFactoryLoader() looking at" << fileName;
}
library = QLibraryPrivate::findOrCreate(QFileInfo(fileName).canonicalFilePath());
if (!library->isPlugin(&settings)) {
if (!library->isPlugin()) {
if (qt_debug_component()) {
qDebug() << library->errorString;
qDebug() << " not a plugin";
@ -135,45 +133,26 @@ void QFactoryLoader::update()
library->release();
continue;
}
QString regkey = QString::fromLatin1("Qt Factory Cache %1.%2/%3:/%4")
.arg((QT_VERSION & 0xff0000) >> 16)
.arg((QT_VERSION & 0xff00) >> 8)
.arg(QLatin1String(d->iid))
.arg(fileName);
QStringList reg, keys;
reg = settings.value(regkey).toStringList();
if (reg.count() && library->lastModified == reg[0]) {
keys = reg;
keys.removeFirst();
} else {
if (!library->loadPlugin()) {
if (qt_debug_component()) {
qDebug() << library->errorString;
qDebug() << " could not load";
}
library->release();
continue;
QStringList keys;
if (!library->loadPlugin()) {
if (qt_debug_component()) {
qDebug() << library->errorString;
qDebug() << " could not load";
}
QObject *instance = library->instance();
if (!instance) {
library->release();
// ignore plugins that have a valid signature but cannot be loaded.
continue;
}
QFactoryInterface *factory = qobject_cast<QFactoryInterface*>(instance);
if (instance && factory && instance->qt_metacast(d->iid))
keys = factory->keys();
if (keys.isEmpty())
library->unload();
reg.clear();
reg << library->lastModified;
reg += keys;
settings.setValue(regkey, reg);
library->release();
continue;
}
if (qt_debug_component()) {
qDebug() << "keys" << keys;
QObject *instance = library->instance();
if (!instance) {
library->release();
// ignore plugins that have a valid signature but cannot be loaded.
continue;
}
QFactoryInterface *factory = qobject_cast<QFactoryInterface*>(instance);
if (instance && factory && instance->qt_metacast(d->iid))
keys = factory->keys();
if (keys.isEmpty())
library->unload();
if (keys.isEmpty()) {
library->release();
continue;

View File

@ -50,8 +50,6 @@
#include <qfileinfo.h>
#include <qmutex.h>
#include <qmap.h>
#include <qsettings.h>
#include <qdatetime.h>
#include <private/qcoreapplication_p.h>
#ifdef Q_OS_MAC
# include <private/qcore_mac_p.h>
@ -648,7 +646,7 @@ bool qt_get_verificationdata(QtPluginQueryVerificationDataFunction pfn, uint *qt
return qt_parse_pattern(szData, qt_version, debug);
}
bool QLibraryPrivate::isPlugin(QSettings *settings)
bool QLibraryPrivate::isPlugin()
{
errorString.clear();
if (pluginState != MightBeAPlugin)
@ -672,135 +670,88 @@ bool QLibraryPrivate::isPlugin(QSettings *settings)
}
#endif
QFileInfo fileinfo(fileName);
#ifndef QT_NO_DATESTRING
lastModified = fileinfo.lastModified().toString(Qt::ISODate);
#endif
QString regkey = QString::fromLatin1("Qt Plugin Cache %1.%2.%3/%4")
.arg((QT_VERSION & 0xff0000) >> 16)
.arg((QT_VERSION & 0xff00) >> 8)
.arg(QLIBRARY_AS_DEBUG ? QLatin1String("debug") : QLatin1String("false"))
.arg(fileName);
#ifdef Q_WS_MAC
// On Mac, add the application arch to the reg key in order to
// cache plugin information separately for each arch. This prevents
// Qt from wrongly caching plugin load failures when the archs
// don't match.
#if defined(__x86_64__)
regkey += QLatin1String("-x86_64");
#elif defined(__i386__)
regkey += QLatin1String("-i386");
#elif defined(__ppc64__)
regkey += QLatin1String("-ppc64");
#elif defined(__ppc__)
regkey += QLatin1String("-ppc");
#endif
#endif // Q_WS_MAC
QStringList reg;
#ifndef QT_NO_SETTINGS
if (!settings) {
settings = QCoreApplicationPrivate::trolltechConf();
}
reg = settings->value(regkey).toStringList();
#endif
if (reg.count() == 3 && lastModified == reg.at(2)) {
qt_version = reg.at(0).toUInt(0, 16);
debug = bool(reg.at(1).toInt());
success = qt_version != 0;
} else {
#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC) && !defined(Q_OS_SYMBIAN)
if (!pHnd) {
// use unix shortcut to avoid loading the library
success = qt_unix_query(fileName, &qt_version, &debug, this);
} else
if (!pHnd) {
// use unix shortcut to avoid loading the library
success = qt_unix_query(fileName, &qt_version, &debug, this);
} else
#endif
{
bool retryLoadLibrary = false; // Only used on Windows with MS compiler.(false in other cases)
do {
bool temporary_load = false;
{
bool retryLoadLibrary = false; // Only used on Windows with MS compiler.(false in other cases)
do {
bool temporary_load = false;
#ifdef Q_OS_WIN
HMODULE hTempModule = 0;
HMODULE hTempModule = 0;
#endif
if (!pHnd) {
if (!pHnd) {
#ifdef Q_OS_WIN
DWORD dwFlags = (retryLoadLibrary) ? 0: DONT_RESOLVE_DLL_REFERENCES;
//avoid 'Bad Image' message box
UINT oldmode = SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
hTempModule = ::LoadLibraryEx((wchar_t*)QDir::toNativeSeparators(fileName).utf16(), 0, dwFlags);
SetErrorMode(oldmode);
DWORD dwFlags = (retryLoadLibrary) ? 0: DONT_RESOLVE_DLL_REFERENCES;
//avoid 'Bad Image' message box
UINT oldmode = SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
hTempModule = ::LoadLibraryEx((wchar_t*)QDir::toNativeSeparators(fileName).utf16(), 0, dwFlags);
SetErrorMode(oldmode);
#else
# if defined(Q_OS_SYMBIAN)
//Guard against accidentally trying to load non-plugin libraries by making sure the stub exists
if (fileinfo.exists())
//Guard against accidentally trying to load non-plugin libraries by making sure the stub exists
if (fileinfo.exists())
# endif
temporary_load = load_sys();
temporary_load = load_sys();
#endif
}
}
#ifdef Q_OS_WIN
QtPluginQueryVerificationDataFunction qtPluginQueryVerificationDataFunction = hTempModule ? (QtPluginQueryVerificationDataFunction)
QtPluginQueryVerificationDataFunction qtPluginQueryVerificationDataFunction = hTempModule ? (QtPluginQueryVerificationDataFunction)
#ifdef Q_OS_WINCE
::GetProcAddress(hTempModule, L"qt_plugin_query_verification_data")
::GetProcAddress(hTempModule, L"qt_plugin_query_verification_data")
#else
::GetProcAddress(hTempModule, "qt_plugin_query_verification_data")
::GetProcAddress(hTempModule, "qt_plugin_query_verification_data")
#endif
: (QtPluginQueryVerificationDataFunction) resolve("qt_plugin_query_verification_data");
: (QtPluginQueryVerificationDataFunction) resolve("qt_plugin_query_verification_data");
#else
QtPluginQueryVerificationDataFunction qtPluginQueryVerificationDataFunction = NULL;
QtPluginQueryVerificationDataFunction qtPluginQueryVerificationDataFunction = NULL;
# if defined(Q_OS_SYMBIAN)
if (temporary_load) {
qtPluginQueryVerificationDataFunction = (QtPluginQueryVerificationDataFunction) resolve("qt_plugin_query_verification_data");
// If resolving with function name failed (i.e. not STDDLL), try resolving using known ordinal
if (!qtPluginQueryVerificationDataFunction)
qtPluginQueryVerificationDataFunction = (QtPluginQueryVerificationDataFunction) resolve("1");
}
# else
if (temporary_load) {
qtPluginQueryVerificationDataFunction = (QtPluginQueryVerificationDataFunction) resolve("qt_plugin_query_verification_data");
// If resolving with function name failed (i.e. not STDDLL), try resolving using known ordinal
if (!qtPluginQueryVerificationDataFunction)
qtPluginQueryVerificationDataFunction = (QtPluginQueryVerificationDataFunction) resolve("1");
}
# else
qtPluginQueryVerificationDataFunction = (QtPluginQueryVerificationDataFunction) resolve("qt_plugin_query_verification_data");
# endif
#endif
bool exceptionThrown = false;
bool ret = qt_get_verificationdata(qtPluginQueryVerificationDataFunction,
&qt_version, &debug, &exceptionThrown);
if (!exceptionThrown) {
if (!ret) {
qt_version = 0;
if (temporary_load)
unload_sys();
} else {
success = true;
}
retryLoadLibrary = false;
bool exceptionThrown = false;
bool ret = qt_get_verificationdata(qtPluginQueryVerificationDataFunction,
&qt_version, &debug, &exceptionThrown);
if (!exceptionThrown) {
if (!ret) {
qt_version = 0;
if (temporary_load)
unload_sys();
} else {
success = true;
}
retryLoadLibrary = false;
}
#ifdef QT_USE_MS_STD_EXCEPTION
else {
// An exception was thrown when calling qt_plugin_query_verification_data().
// This usually happens when plugin is compiled with the /clr compiler flag,
// & will only work if the dependencies are loaded & DLLMain() is called.
// LoadLibrary() will do this, try once with this & if it fails dont load.
retryLoadLibrary = !retryLoadLibrary;
}
else {
// An exception was thrown when calling qt_plugin_query_verification_data().
// This usually happens when plugin is compiled with the /clr compiler flag,
// & will only work if the dependencies are loaded & DLLMain() is called.
// LoadLibrary() will do this, try once with this & if it fails dont load.
retryLoadLibrary = !retryLoadLibrary;
}
#endif
#ifdef Q_OS_WIN
if (hTempModule) {
BOOL ok = ::FreeLibrary(hTempModule);
if (ok) {
hTempModule = 0;
}
if (hTempModule) {
BOOL ok = ::FreeLibrary(hTempModule);
if (ok) {
hTempModule = 0;
}
#endif
} while(retryLoadLibrary); // Will be 'false' in all cases other than when an
// exception is thrown(will happen only when using a MS compiler)
}
#ifndef QT_NO_SETTINGS
QStringList queried;
queried << QString::number(qt_version,16)
<< QString::number((int)debug)
<< lastModified;
settings->setValue(regkey, queried);
}
#endif
} while (retryLoadLibrary); // Will be 'false' in all cases other than when an
// exception is thrown(will happen only when using a MS compiler)
}
if (!success) {

View File

@ -68,7 +68,6 @@ QT_BEGIN_NAMESPACE
bool qt_debug_component();
class QSettings;
class QLibraryPrivate
{
public:
@ -99,7 +98,7 @@ public:
QString errorString;
QLibrary::LoadHints loadHints;
bool isPlugin(QSettings *settings = 0);
bool isPlugin();
private:

View File

@ -98,22 +98,6 @@ QT_BEGIN_NAMESPACE
every instance has called unload(). Right before the unloading
happen, the root component will also be deleted.
In order to speed up loading and validation of plugins, some of
the information that is collected during loading is cached in
persistent memory (through QSettings). For instance, the result
of a load operation (e.g. succeeded or failed) is stored in the
cache, so that subsequent load operations don't try to load an
invalid plugin. However, if the "last modified" timestamp of
a plugin has changed, the plugin's cache entry is invalidated
and the plugin is reloaded regardless of the values in the cache
entry. The cache entry is then updated with the new result of the
load operation.
This also means that the timestamp must be updated each time the
plugin or any dependent resources (such as a shared library) is
updated, since the dependent resources might influence the result
of loading a plugin.
See \l{How to Create Qt Plugins} for more information about
how to make your application extensible through plugins.