From 9fb639a00e1a809a9ea9b5e68777ec46f534761c Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Sun, 24 May 2020 13:27:40 +0200 Subject: Update ModInfo to use a single file tree for all content-related operations. --- src/modinfowithconflictinfo.cpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'src/modinfowithconflictinfo.cpp') diff --git a/src/modinfowithconflictinfo.cpp b/src/modinfowithconflictinfo.cpp index 0c67b4f7..45ecffb7 100644 --- a/src/modinfowithconflictinfo.cpp +++ b/src/modinfowithconflictinfo.cpp @@ -296,14 +296,30 @@ bool ModInfoWithConflictInfo::hasHiddenFiles() const return m_HasHiddenFiles; } +void ModInfoWithConflictInfo::diskContentModified() { + std::unique_lock lock(m_Mutex); + m_FileTree = nullptr; +} + +std::shared_ptr ModInfoWithConflictInfo::contentFileTree() const { + std::unique_lock lock(m_Mutex); + if (!m_FileTree) { + m_FileTree = QDirFileTree::makeTree(absolutePath()); + } + return m_FileTree; +} bool ModInfoWithConflictInfo::doTestValid() const { auto mdc = m_GamePlugin->feature(); if (mdc) { - auto qdirfiletree = QDirFileTree::makeTree(absolutePath()); + auto qdirfiletree = contentFileTree(); return mdc->dataLooksValid(qdirfiletree); } return true; } + +bool ModInfoWithConflictInfo::isValid() const { + return doTestValid(); +} -- cgit v1.3.1 From 4bcb92fc47181c62af62a55377b62dcfa02252ae Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Sun, 24 May 2020 14:49:51 +0200 Subject: Use a more generic 'prefetch' method instead of isValid(). --- src/modinfo.cpp | 2 +- src/modinfo.h | 12 ++++++++++++ src/modinfowithconflictinfo.cpp | 5 +++++ src/modinfowithconflictinfo.h | 9 +++++++++ 4 files changed, 27 insertions(+), 1 deletion(-) (limited to 'src/modinfowithconflictinfo.cpp') diff --git a/src/modinfo.cpp b/src/modinfo.cpp index eb0f0b4f..15fa71da 100644 --- a/src/modinfo.cpp +++ b/src/modinfo.cpp @@ -288,7 +288,7 @@ void ModInfo::updateFromDisc(const QString &modDirectory, std::sort(s_Collection.begin(), s_Collection.end(), ModInfo::ByName); - parallelMap(std::begin(s_Collection), std::end(s_Collection), &ModInfo::isValid, refreshThreadCount); + parallelMap(std::begin(s_Collection), std::end(s_Collection), &ModInfo::prefetch, refreshThreadCount); updateIndices(); diff --git a/src/modinfo.h b/src/modinfo.h index 37a2d24d..29e6124d 100644 --- a/src/modinfo.h +++ b/src/modinfo.h @@ -815,8 +815,20 @@ signals: protected: + /** + * + */ ModInfo(PluginContainer *pluginContainer); + /** + * @brief Prefetch content for this mod. + * + * This method can be used to prefetch content from the mod, e.g., for isValid() + * or getContents(). This method will only be called when first creating the mod + * using multiple threads for all the mods. + */ + virtual void prefetch() = 0; + static void updateIndices(); static bool ByName(const ModInfo::Ptr &LHS, const ModInfo::Ptr &RHS); diff --git a/src/modinfowithconflictinfo.cpp b/src/modinfowithconflictinfo.cpp index 45ecffb7..d2202c3d 100644 --- a/src/modinfowithconflictinfo.cpp +++ b/src/modinfowithconflictinfo.cpp @@ -309,6 +309,11 @@ std::shared_ptr ModInfoWithConflictInfo::contentFileTree() cons return m_FileTree; } +void ModInfoWithConflictInfo::prefetch() { + // Populating the tree to 1-depth: + contentFileTree()->size(); +} + bool ModInfoWithConflictInfo::doTestValid() const { auto mdc = m_GamePlugin->feature(); diff --git a/src/modinfowithconflictinfo.h b/src/modinfowithconflictinfo.h index 5bc1d585..68675397 100644 --- a/src/modinfowithconflictinfo.h +++ b/src/modinfowithconflictinfo.h @@ -108,6 +108,15 @@ private: protected: + /** + * @brief Prefetch content for this mod. + * + * This method can be used to prefetch content from the mod, e.g., for isValid() + * or getContents(). This method will only be called when first creating the mod + * using multiple threads for all the mods. + */ + virtual void prefetch() override; + // Current game plugin running in MO2: MOBase::IPluginGame const * const m_GamePlugin; -- cgit v1.3.1 From 238e233c18d22d01e966efaa86975f5f37bb7fa2 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Sun, 24 May 2020 23:33:21 +0200 Subject: Use memoization for file tree, contents and validity of ModInfo. --- src/modinforegular.cpp | 3 +-- src/modinforegular.h | 4 ++-- src/modinfowithconflictinfo.cpp | 25 ++++++++++++++++--------- src/modinfowithconflictinfo.h | 31 ++++++++++++++++++++++++------- 4 files changed, 43 insertions(+), 20 deletions(-) (limited to 'src/modinfowithconflictinfo.cpp') diff --git a/src/modinforegular.cpp b/src/modinforegular.cpp index 87483a64..d8e42383 100644 --- a/src/modinforegular.cpp +++ b/src/modinforegular.cpp @@ -653,7 +653,7 @@ std::vector ModInfoRegular::getFlags() const } -std::vector ModInfoRegular::getContents() const +std::vector ModInfoRegular::doGetContents() const { auto tree = contentFileTree(); std::vector contents; @@ -707,7 +707,6 @@ std::vector ModInfoRegular::getContents() const } return contents; - } diff --git a/src/modinforegular.h b/src/modinforegular.h index 08546c69..e63e7570 100644 --- a/src/modinforegular.h +++ b/src/modinforegular.h @@ -289,8 +289,6 @@ public: */ virtual std::vector getFlags() const override; - virtual std::vector getContents() const override; - /** * @return an indicator if and how this mod should be highlighted by the UI */ @@ -418,6 +416,8 @@ private slots: protected: + virtual std::vector doGetContents() const override; + ModInfoRegular(PluginContainer *pluginContainer, const MOBase::IPluginGame *game, const QDir &path, MOShared::DirectoryEntry **directoryStructure); private: diff --git a/src/modinfowithconflictinfo.cpp b/src/modinfowithconflictinfo.cpp index d2202c3d..d2a0ca51 100644 --- a/src/modinfowithconflictinfo.cpp +++ b/src/modinfowithconflictinfo.cpp @@ -14,7 +14,9 @@ namespace fs = std::filesystem; ModInfoWithConflictInfo::ModInfoWithConflictInfo( PluginContainer *pluginContainer, const MOBase::IPluginGame* gamePlugin, DirectoryEntry **directoryStructure) - : ModInfo(pluginContainer), m_GamePlugin(gamePlugin), m_DirectoryStructure(directoryStructure), m_HasLooseOverwrite(false), m_HasHiddenFiles(false) {} + : ModInfo(pluginContainer), m_GamePlugin(gamePlugin), + m_FileTree(&ModInfoWithConflictInfo::updateFileTree), m_Valid(&ModInfoWithConflictInfo::doTestValid), m_Contents(&ModInfoWithConflictInfo::doGetContents), + m_DirectoryStructure(directoryStructure), m_HasLooseOverwrite(false), m_HasHiddenFiles(false) {} void ModInfoWithConflictInfo::clearCaches() { @@ -297,16 +299,17 @@ bool ModInfoWithConflictInfo::hasHiddenFiles() const } void ModInfoWithConflictInfo::diskContentModified() { - std::unique_lock lock(m_Mutex); - m_FileTree = nullptr; + m_FileTree.invalidate(); + m_Valid.invalidate(); + m_Contents.invalidate(); +} + +std::shared_ptr ModInfoWithConflictInfo::updateFileTree() const { + return QDirFileTree::makeTree(absolutePath()); } std::shared_ptr ModInfoWithConflictInfo::contentFileTree() const { - std::unique_lock lock(m_Mutex); - if (!m_FileTree) { - m_FileTree = QDirFileTree::makeTree(absolutePath()); - } - return m_FileTree; + return m_FileTree.value(this); } void ModInfoWithConflictInfo::prefetch() { @@ -326,5 +329,9 @@ bool ModInfoWithConflictInfo::doTestValid() const { } bool ModInfoWithConflictInfo::isValid() const { - return doTestValid(); + return m_Valid.value(this); +} + +std::vector ModInfoWithConflictInfo::getContents() const { + return m_Contents.value(this); } diff --git a/src/modinfowithconflictinfo.h b/src/modinfowithconflictinfo.h index 68675397..3adbb998 100644 --- a/src/modinfowithconflictinfo.h +++ b/src/modinfowithconflictinfo.h @@ -3,6 +3,7 @@ #include +#include "thread_utils.h" #include "modinfo.h" #include @@ -20,6 +21,11 @@ public: **/ virtual bool isValid() const override; + /** + * @return a list of content types contained in a mod + */ + virtual std::vector getContents() const override; + /** * @brief clear all caches held for this mod */ @@ -49,12 +55,19 @@ public slots: protected: /** - * @brief check if the content of this mod is valid. + * @brief Check if the content of this mod is valid. * - * @return true if the content is valid, false otherwize. + * @return true if the content is valid, false otherwise. **/ virtual bool doTestValid() const; + /** + * @brief Compute the contents for this mod. + * + * @return the contents for this mod. + **/ + virtual std::vector doGetContents() const { return {}; } + /** * @brief Retrieve a file tree corresponding to the underlying disk content * of this mod. @@ -122,12 +135,16 @@ protected: private: - // Mutex: - mutable std::mutex m_Mutex; + /** + * @return a file tree for this mod. + */ + std::shared_ptr updateFileTree() const; - // File tree representing the content of the disk. A null pointer indicates - // that the content needs to be loaded from the disk: - mutable std::shared_ptr m_FileTree = nullptr; + MOShared::MemoizedLocked< + std::shared_ptr, + decltype(&ModInfoWithConflictInfo::updateFileTree)> m_FileTree; + MOShared::MemoizedLocked m_Valid; + MOShared::MemoizedLocked, decltype(&ModInfoWithConflictInfo::doGetContents)> m_Contents; MOShared::DirectoryEntry **m_DirectoryStructure; -- cgit v1.3.1 From 03fc2b0dc25ae00322c6681d99f48857ecf77935 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Mon, 25 May 2020 17:57:07 +0200 Subject: Update ModInfo classes following MemoizedLocked changes. --- src/modinfoseparator.h | 2 +- src/modinfowithconflictinfo.cpp | 22 ++++++++++------------ src/modinfowithconflictinfo.h | 15 ++++----------- 3 files changed, 15 insertions(+), 24 deletions(-) (limited to 'src/modinfowithconflictinfo.cpp') diff --git a/src/modinfoseparator.h b/src/modinfoseparator.h index 4cfb9ea0..a7a6cb5f 100644 --- a/src/modinfoseparator.h +++ b/src/modinfoseparator.h @@ -49,7 +49,7 @@ public: virtual void addInstalledFile(int /*modId*/, int /*fileId*/) override { } protected: - virtual bool doTestValid() const override { return true; } + virtual bool doIsValid() const override { return true; } private: diff --git a/src/modinfowithconflictinfo.cpp b/src/modinfowithconflictinfo.cpp index d2a0ca51..7181bef9 100644 --- a/src/modinfowithconflictinfo.cpp +++ b/src/modinfowithconflictinfo.cpp @@ -15,7 +15,9 @@ namespace fs = std::filesystem; ModInfoWithConflictInfo::ModInfoWithConflictInfo( PluginContainer *pluginContainer, const MOBase::IPluginGame* gamePlugin, DirectoryEntry **directoryStructure) : ModInfo(pluginContainer), m_GamePlugin(gamePlugin), - m_FileTree(&ModInfoWithConflictInfo::updateFileTree), m_Valid(&ModInfoWithConflictInfo::doTestValid), m_Contents(&ModInfoWithConflictInfo::doGetContents), + m_FileTree([this]() { return QDirFileTree::makeTree(absolutePath()); }), + m_Valid([this]() { return doIsValid(); }), + m_Contents([this]() { return doGetContents(); }), m_DirectoryStructure(directoryStructure), m_HasLooseOverwrite(false), m_HasHiddenFiles(false) {} void ModInfoWithConflictInfo::clearCaches() @@ -304,20 +306,12 @@ void ModInfoWithConflictInfo::diskContentModified() { m_Contents.invalidate(); } -std::shared_ptr ModInfoWithConflictInfo::updateFileTree() const { - return QDirFileTree::makeTree(absolutePath()); -} - -std::shared_ptr ModInfoWithConflictInfo::contentFileTree() const { - return m_FileTree.value(this); -} - void ModInfoWithConflictInfo::prefetch() { // Populating the tree to 1-depth: contentFileTree()->size(); } -bool ModInfoWithConflictInfo::doTestValid() const { +bool ModInfoWithConflictInfo::doIsValid() const { auto mdc = m_GamePlugin->feature(); if (mdc) { @@ -328,10 +322,14 @@ bool ModInfoWithConflictInfo::doTestValid() const { return true; } +std::shared_ptr ModInfoWithConflictInfo::contentFileTree() const { + return m_FileTree.value(); +} + bool ModInfoWithConflictInfo::isValid() const { - return m_Valid.value(this); + return m_Valid.value(); } std::vector ModInfoWithConflictInfo::getContents() const { - return m_Contents.value(this); + return m_Contents.value(); } diff --git a/src/modinfowithconflictinfo.h b/src/modinfowithconflictinfo.h index 3adbb998..abc9f223 100644 --- a/src/modinfowithconflictinfo.h +++ b/src/modinfowithconflictinfo.h @@ -59,7 +59,7 @@ protected: * * @return true if the content is valid, false otherwise. **/ - virtual bool doTestValid() const; + virtual bool doIsValid() const; /** * @brief Compute the contents for this mod. @@ -135,16 +135,9 @@ protected: private: - /** - * @return a file tree for this mod. - */ - std::shared_ptr updateFileTree() const; - - MOShared::MemoizedLocked< - std::shared_ptr, - decltype(&ModInfoWithConflictInfo::updateFileTree)> m_FileTree; - MOShared::MemoizedLocked m_Valid; - MOShared::MemoizedLocked, decltype(&ModInfoWithConflictInfo::doGetContents)> m_Contents; + MOShared::MemoizedLocked> m_FileTree; + MOShared::MemoizedLocked m_Valid; + MOShared::MemoizedLocked> m_Contents; MOShared::DirectoryEntry **m_DirectoryStructure; -- cgit v1.3.1 From 09e75d14e561ae58db0ca8fdb37921c40fa8d420 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Mon, 25 May 2020 17:59:07 +0200 Subject: Fix comment for prefetch(). --- src/modinfowithconflictinfo.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/modinfowithconflictinfo.cpp') diff --git a/src/modinfowithconflictinfo.cpp b/src/modinfowithconflictinfo.cpp index 7181bef9..b0edf581 100644 --- a/src/modinfowithconflictinfo.cpp +++ b/src/modinfowithconflictinfo.cpp @@ -307,7 +307,8 @@ void ModInfoWithConflictInfo::diskContentModified() { } void ModInfoWithConflictInfo::prefetch() { - // Populating the tree to 1-depth: + // Populating the tree to 1-depth (IFileTree is lazy, so size() forces the + // tree to populate the first level): contentFileTree()->size(); } -- cgit v1.3.1