diff --git a/src/plugins/qt4projectmanager/profilereader.cpp b/src/plugins/qt4projectmanager/profilereader.cpp index b5b447ad602c76f42273d283487f91fccbd055cb..90c6241b1bf2409ce2ad086c430608c8cda7cb85 100644 --- a/src/plugins/qt4projectmanager/profilereader.cpp +++ b/src/plugins/qt4projectmanager/profilereader.cpp @@ -42,35 +42,27 @@ ProFileReader::ProFileReader(ProFileOption *option) : ProFileEvaluator(option) ProFileReader::~ProFileReader() { foreach (ProFile *pf, m_proFiles) - delete pf; + pf->deref(); } bool ProFileReader::readProFile(const QString &fileName) { - //disable caching -> list of include files is not updated otherwise - ProFile *pro = new ProFile(fileName); - if (!queryProFile(pro)) { - delete pro; - return false; + if (ProFile *pro = parsedProFile(fileName)) { + aboutToEval(pro); + bool ok = accept(pro); + pro->deref(); + return ok; } - m_includeFiles.insert(fileName, pro); - m_proFiles.append(pro); - return accept(pro); + return false; } -ProFile *ProFileReader::parsedProFile(const QString &fileName) +void ProFileReader::aboutToEval(ProFile *pro) { - ProFile *pro = ProFileEvaluator::parsedProFile(fileName); - if (pro) { - m_includeFiles.insert(fileName, pro); + if (!m_includeFiles.contains(pro->fileName())) { + m_includeFiles.insert(pro->fileName(), pro); m_proFiles.append(pro); + pro->ref(); } - return pro; -} - -void ProFileReader::releaseParsedProFile(ProFile *) -{ - return; } QList<ProFile*> ProFileReader::includeFiles() const @@ -117,3 +109,52 @@ ProFile *ProFileReader::proFileFor(const QString &name) { return m_includeFiles.value(name); } + + + +ProFileCacheManager *ProFileCacheManager::s_instance = 0; + +ProFileCacheManager::ProFileCacheManager(QObject *parent) : + QObject(parent), + m_cache(0) +{ + s_instance = this; + m_timer.setSingleShot(true); + m_timer.setInterval(5000); + connect(&m_timer, SIGNAL(timeout()), SLOT(clear())); +} + +ProFileCacheManager::~ProFileCacheManager() +{ + s_instance = 0; + clear(); +} + +ProFileCache *ProFileCacheManager::cache() +{ + m_timer.start(); + if (!m_cache) + m_cache = new ProFileCache; + return m_cache; +} + +void ProFileCacheManager::clear() +{ + // Just deleting the cache will be safe as long as the sequence of + // obtaining a cache pointer and using it is atomic as far as the main + // loop is concerned. Use a shared pointer once this is not true anymore. + delete m_cache; + m_cache = 0; +} + +void ProFileCacheManager::discardFiles(const QString &prefix) +{ + if (m_cache) + m_cache->discardFiles(prefix); +} + +void ProFileCacheManager::discardFile(const QString &fileName) +{ + if (m_cache) + m_cache->discardFile(fileName); +} diff --git a/src/plugins/qt4projectmanager/profilereader.h b/src/plugins/qt4projectmanager/profilereader.h index 7e927d181b214acdb77dc9c5a1ea4174ab2a0162..f77df8d890009dda2c3a6ab1c44b4f8616c7c473 100644 --- a/src/plugins/qt4projectmanager/profilereader.h +++ b/src/plugins/qt4projectmanager/profilereader.h @@ -34,6 +34,7 @@ #include <QtCore/QObject> #include <QtCore/QMap> +#include <QtCore/QTimer> namespace Qt4ProjectManager { namespace Internal { @@ -56,8 +57,7 @@ signals: void errorFound(const QString &error); private: - virtual ProFile *parsedProFile(const QString &fileName); - virtual void releaseParsedProFile(ProFile *proFile); + virtual void aboutToEval(ProFile *proFile); virtual void logMessage(const QString &msg); virtual void fileMessage(const QString &msg); virtual void errorMessage(const QString &msg); @@ -67,6 +67,28 @@ private: QList<ProFile *> m_proFiles; }; +class ProFileCacheManager : public QObject +{ + Q_OBJECT + +public: + static ProFileCacheManager *instance() { return s_instance; } + ProFileCache *cache(); + void discardFiles(const QString &prefix); + void discardFile(const QString &fileName); + +private: + ProFileCacheManager(QObject *parent); + ~ProFileCacheManager(); + Q_SLOT void clear(); + QTimer m_timer; + ProFileCache *m_cache; + + static ProFileCacheManager *s_instance; + + friend class Qt4ProjectManagerPlugin; +}; + } // namespace Internal } // namespace Qt4ProjectManager diff --git a/src/plugins/qt4projectmanager/qt4nodes.cpp b/src/plugins/qt4projectmanager/qt4nodes.cpp index f4f228f6e11a0f7b15e0cc41a69c7c7c17855b9c..4da6c377c629d11a5da6da7a6e4909295d6add10 100644 --- a/src/plugins/qt4projectmanager/qt4nodes.cpp +++ b/src/plugins/qt4projectmanager/qt4nodes.cpp @@ -115,6 +115,7 @@ Qt4PriFileNode::Qt4PriFileNode(Qt4Project *project, Qt4ProFileNode* qt4ProFileNo void Qt4PriFileNode::scheduleUpdate() { + ProFileCacheManager::instance()->discardFile(m_projectFilePath); m_qt4ProFileNode->scheduleUpdate(); } diff --git a/src/plugins/qt4projectmanager/qt4project.cpp b/src/plugins/qt4projectmanager/qt4project.cpp index 1d9a753dbc86d2bee3d88b6ccf6f5633fde4568c..d0f9941246ceaabf0e0ff2bff9b26dad9a272f11 100644 --- a/src/plugins/qt4projectmanager/qt4project.cpp +++ b/src/plugins/qt4projectmanager/qt4project.cpp @@ -867,6 +867,8 @@ ProFileReader *Qt4Project::createProFileReader(Qt4ProFileNode *qt4ProFileNode) if (version->isValid()) m_proFileOption->properties = version->versionInfo(); } + + m_proFileOption->cache = ProFileCacheManager::instance()->cache(); } ++m_proFileOptionRefCnt; @@ -883,6 +885,11 @@ void Qt4Project::destroyProFileReader(ProFileReader *reader) { delete reader; if (!--m_proFileOptionRefCnt) { + QString dir = QFileInfo(m_fileInfo->fileName()).absolutePath(); + if (!dir.endsWith(QLatin1Char('/'))) + dir += QLatin1Char('/'); + m_proFileOption->cache->discardFiles(dir); + delete m_proFileOption; m_proFileOption = 0; } @@ -1040,8 +1047,10 @@ void Qt4Project::notifyChanged(const QString &name) if (files(Qt4Project::ExcludeGeneratedFiles).contains(name)) { QList<Qt4ProFileNode *> list; findProFile(name, rootProjectNode(), list); - foreach(Qt4ProFileNode *node, list) + foreach(Qt4ProFileNode *node, list) { + ProFileCacheManager::instance()->discardFile(name); node->update(); + } } } diff --git a/src/plugins/qt4projectmanager/qt4projectmanagerplugin.cpp b/src/plugins/qt4projectmanager/qt4projectmanagerplugin.cpp index 040691c56a0e3b23b95b99b3a3b251b1f4c1f75c..5261ee74e02904ae6cda091cc157b9ec2e2d94e9 100644 --- a/src/plugins/qt4projectmanager/qt4projectmanagerplugin.cpp +++ b/src/plugins/qt4projectmanager/qt4projectmanagerplugin.cpp @@ -169,6 +169,8 @@ bool Qt4ProjectManagerPlugin::initialize(const QStringList &arguments, QString * addAutoReleasedObject(MaemoManager::instance()); #endif + new ProFileCacheManager(this); + // TODO reenable //m_embeddedPropertiesPage = new EmbeddedPropertiesPage; //addObject(m_embeddedPropertiesPage); diff --git a/src/plugins/qt4projectmanager/qtversionmanager.cpp b/src/plugins/qt4projectmanager/qtversionmanager.cpp index db1888399f025050eebc8afeb17ebad5e7fbec51..48f59817692df638af7a0f87df3916c8b17540af 100644 --- a/src/plugins/qt4projectmanager/qtversionmanager.cpp +++ b/src/plugins/qt4projectmanager/qtversionmanager.cpp @@ -1207,6 +1207,7 @@ void QtVersion::updateToolChainAndMkspec() const ProFileOption option; option.properties = versionInfo(); + option.cache = ProFileCacheManager::instance()->cache(); ProFileReader *reader = new ProFileReader(&option); reader->setCumulative(false); reader->setParsePreAndPostFiles(false); diff --git a/src/shared/proparser/profileevaluator.cpp b/src/shared/proparser/profileevaluator.cpp index 035e7d4c234a1f7d4670523675606a4c8eca7387..7c8c5bfa179750f17312135afa3af9e82d48a787 100644 --- a/src/shared/proparser/profileevaluator.cpp +++ b/src/shared/proparser/profileevaluator.cpp @@ -85,11 +85,59 @@ static void clearFunctions(ProFileEvaluator::FunctionDefs *defs) /////////////////////////////////////////////////////////////////////// // -// ProFileOption +// ProFileCache // /////////////////////////////////////////////////////////////////////// +ProFileCache::~ProFileCache() +{ + foreach (ProFile *pro, parsed_files) + pro->deref(); +} + +void ProFileCache::discardFile(const QString &fileName) +{ + QHash<QString, ProFile *>::Iterator it = parsed_files.find(fileName); + if (it != parsed_files.end()) { + it.value()->deref(); + parsed_files.erase(it); + } +} + +void ProFileCache::discardFiles(const QString &prefix) +{ + QHash<QString, ProFile *>::Iterator + it = parsed_files.begin(), + end = parsed_files.end(); + while (it != end) + if (it.key().startsWith(prefix)) { + it.value()->deref(); + it = parsed_files.erase(it); + } else { + ++it; + } +} + +void ProFileCache::addFile(ProFile *pro) +{ + parsed_files[pro->fileName()] = pro; + pro->ref(); +} + +ProFile *ProFileCache::getFile(const QString &fileName) +{ + ProFile *pro = parsed_files.value(fileName); + if (pro) + pro->ref(); + return pro; +} + +/////////////////////////////////////////////////////////////////////// +// // ProFileOption +// +/////////////////////////////////////////////////////////////////////// + ProFileOption::ProFileOption() { #ifdef Q_OS_WIN @@ -112,6 +160,8 @@ ProFileOption::ProFileOption() #endif field_sep = QLatin1String(" "); + + cache = 0; } ProFileOption::~ProFileOption() @@ -199,6 +249,8 @@ public: ProFile *currentProFile() const; ProItem::ProItemReturn evaluateConditionalFunction(const QString &function, const QString &arguments); + ProFile *parsedProFile(const QString &fileName, bool cache, + const QString &contents = QString()); bool evaluateFile(const QString &fileName); bool evaluateFeatureFile(const QString &fileName, QHash<QString, QStringList> *values = 0, FunctionDefs *defs = 0); @@ -2776,20 +2828,20 @@ QStringList ProFileEvaluator::Private::values(const QString &variableName, const return values(variableName, m_filevaluemap[pro], pro); } -// virtual -ProFile *ProFileEvaluator::parsedProFile(const QString &fileName) -{ - ProFile *pro = new ProFile(fileName); - if (d->read(pro)) - return pro; - delete pro; - return 0; -} - -// virtual -void ProFileEvaluator::releaseParsedProFile(ProFile *proFile) +ProFile *ProFileEvaluator::Private::parsedProFile(const QString &fileName, bool cache, + const QString &contents) { - delete proFile; + ProFile *pro; + if (!m_option->cache || !(pro = m_option->cache->getFile(fileName))) { + pro = new ProFile(fileName); + if (!(contents.isNull() ? read(pro) : read(pro, contents))) { + delete pro; + return 0; + } + if (m_option->cache && cache) + m_option->cache->addFile(pro); + } + return pro; } bool ProFileEvaluator::Private::evaluateFile(const QString &fileName) @@ -2803,10 +2855,10 @@ bool ProFileEvaluator::Private::evaluateFile(const QString &fileName) errorMessage(format("circular inclusion of %1").arg(fn)); return false; } - ProFile *pro = q->parsedProFile(fn); - if (pro) { + if (ProFile *pro = parsedProFile(fn, true)) { + q->aboutToEval(pro); bool ok = (pro->Accept(this) == ProItem::ReturnTrue); - q->releaseParsedProFile(pro); + pro->deref(); return ok; } else { return false; @@ -2857,12 +2909,13 @@ bool ProFileEvaluator::Private::evaluateFeatureFile( bool cumulative = m_cumulative; m_cumulative = false; - // Don't use evaluateFile() here to avoid the virtual parsedProFile(). + // Don't use evaluateFile() here to avoid calling aboutToEval(). // The path is fully normalized already. - ProFile pro(fn); bool ok = false; - if (read(&pro)) - ok = (pro.Accept(this) == ProItem::ReturnTrue); + if (ProFile *pro = parsedProFile(fn, true)) { + ok = (pro->Accept(this) == ProItem::ReturnTrue); + pro->deref(); + } m_cumulative = cumulative; return ok; @@ -3019,14 +3072,9 @@ ProFileEvaluator::TemplateType ProFileEvaluator::templateType() return TT_Unknown; } -bool ProFileEvaluator::queryProFile(ProFile *pro) +ProFile *ProFileEvaluator::parsedProFile(const QString &fileName, const QString &contents) { - return d->read(pro); -} - -bool ProFileEvaluator::queryProFile(ProFile *pro, const QString &content) -{ - return d->read(pro, content); + return d->parsedProFile(fileName, false, contents); } bool ProFileEvaluator::accept(ProFile *pro) @@ -3039,6 +3087,10 @@ QString ProFileEvaluator::propertyValue(const QString &name) const return d->propertyValue(name); } +void ProFileEvaluator::aboutToEval(ProFile *) +{ +} + void ProFileEvaluator::logMessage(const QString &message) { qWarning("%s", qPrintable(message)); diff --git a/src/shared/proparser/profileevaluator.h b/src/shared/proparser/profileevaluator.h index ee21f4544b69e5d7658e1306153b878eaaa052ad..3537a12a6a4cc8789f139d48dad17998bc2e778d 100644 --- a/src/shared/proparser/profileevaluator.h +++ b/src/shared/proparser/profileevaluator.h @@ -42,6 +42,22 @@ QT_BEGIN_NAMESPACE class ProFileOption; +class ProFileCache +{ +public: + ProFileCache() {} + ~ProFileCache(); + + void addFile(ProFile *pro); + ProFile *getFile(const QString &fileName); + + void discardFile(const QString &fileName); + void discardFiles(const QString &prefix); + +private: + QHash<QString, ProFile *> parsed_files; +}; + class ProFileEvaluator { class Private; @@ -74,8 +90,8 @@ public: void setConfigCommandLineArguments(const QStringList &addUserConfigCmdArgs, const QStringList &removeUserConfigCmdArgs); void setParsePreAndPostFiles(bool on); // Default is true - bool queryProFile(ProFile *pro); - bool queryProFile(ProFile *pro, const QString &content); // the same as above but the content is read from "content" string, not from filesystem + // If contents is non-null, it will be used instead of the file's actual content + ProFile *parsedProFile(const QString &fileName, const QString &contents = QString()); bool accept(ProFile *pro); QStringList values(const QString &variableName) const; @@ -87,8 +103,7 @@ public: QString propertyValue(const QString &val) const; // for our descendents - virtual ProFile *parsedProFile(const QString &fileName); - virtual void releaseParsedProFile(ProFile *proFile); + virtual void aboutToEval(ProFile *proFile); // only .pri, but not .prf. or .pro virtual void logMessage(const QString &msg); virtual void errorMessage(const QString &msg); // .pro parse errors virtual void fileMessage(const QString &msg); // error() and message() from .pro file @@ -130,6 +145,7 @@ struct ProFileOption QString qmakespec; QString cachefile; QHash<QString, QString> properties; + ProFileCache *cache; enum TARG_MODE { TARG_UNIX_MODE, TARG_WIN_MODE, TARG_MACX_MODE, TARG_MAC9_MODE, TARG_QNX6_MODE }; TARG_MODE target_mode;