Merge pull request #6286 from JosJuice/game-list-cache-vector

DolphinWX: Speed up in-memory operations on game list cache
This commit is contained in:
Markus Wick 2018-01-05 23:37:41 +01:00 committed by GitHub
commit 1cf1e7cde0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 35 additions and 31 deletions

View File

@ -10,7 +10,7 @@
#include <cstring> #include <cstring>
#include <memory> #include <memory>
#include <string> #include <string>
#include <unordered_map> #include <unordered_set>
#include <utility> #include <utility>
#include <vector> #include <vector>
#include <wx/app.h> #include <wx/app.h>
@ -760,27 +760,20 @@ void GameListCtrl::RescanList()
const std::vector<std::string> search_extensions = {".gcm", ".tgc", ".iso", ".ciso", ".gcz", const std::vector<std::string> search_extensions = {".gcm", ".tgc", ".iso", ".ciso", ".gcz",
".wbfs", ".wad", ".dol", ".elf"}; ".wbfs", ".wad", ".dol", ".elf"};
// TODO This could process paths iteratively as they are found // TODO This could process paths iteratively as they are found
auto search_results = Common::DoFileSearch(SConfig::GetInstance().m_ISOFolder, search_extensions, const std::vector<std::string> search_results_vector =
SConfig::GetInstance().m_RecursiveISOFolder); Common::DoFileSearch(SConfig::GetInstance().m_ISOFolder, search_extensions,
SConfig::GetInstance().m_RecursiveISOFolder);
// Copy search results into a set, except ones that match DiscIO::ShouldHideFromGameList.
// TODO Prevent DoFileSearch from looking inside /files/ directories of DirectoryBlobs at all? // TODO Prevent DoFileSearch from looking inside /files/ directories of DirectoryBlobs at all?
// TODO Make DoFileSearch support filter predicates so we don't have remove things afterwards? // TODO Make DoFileSearch support filter predicates so we don't have remove things afterwards?
search_results.erase( std::unordered_set<std::string> search_results;
std::remove_if(search_results.begin(), search_results.end(), DiscIO::ShouldHideFromGameList), search_results.reserve(search_results_vector.size());
search_results.end()); for (const std::string& path : search_results_vector)
{
std::vector<std::string> cached_paths; if (!DiscIO::ShouldHideFromGameList(path))
for (const auto& file : m_cached_files) search_results.insert(path);
cached_paths.emplace_back(file->GetFileName()); }
std::sort(cached_paths.begin(), cached_paths.end());
std::list<std::string> removed_paths;
std::set_difference(cached_paths.cbegin(), cached_paths.cend(), search_results.cbegin(),
search_results.cend(), std::back_inserter(removed_paths));
std::vector<std::string> new_paths;
std::set_difference(search_results.cbegin(), search_results.cend(), cached_paths.cbegin(),
cached_paths.cend(), std::back_inserter(new_paths));
// Reload the TitleDatabase // Reload the TitleDatabase
{ {
@ -788,24 +781,35 @@ void GameListCtrl::RescanList()
m_title_database = {}; m_title_database = {};
} }
// For now, only scan new_paths. This could cause false negatives (file actively being written),
// but otherwise should be fine.
bool cache_changed = false; bool cache_changed = false;
{ {
std::unique_lock<std::mutex> lk(m_cache_mutex); std::unique_lock<std::mutex> lk(m_cache_mutex);
for (const auto& path : removed_paths)
// Delete paths that aren't in search_results from m_cached_files,
// while simultaneously deleting paths that aren't in m_cached_files from search_results.
// For the sake of speed, we don't care about maintaining the order of m_cached_files.
{ {
auto it = std::find_if(m_cached_files.cbegin(), m_cached_files.cend(), auto it = m_cached_files.begin();
[&path](const std::shared_ptr<GameListItem>& file) { auto end = m_cached_files.end();
return file->GetFileName() == path; while (it != end)
});
if (it != m_cached_files.cend())
{ {
cache_changed = true; if (search_results.erase((*it)->GetFileName()))
m_cached_files.erase(it); {
++it;
}
else
{
cache_changed = true;
--end;
*it = std::move(*end);
}
} }
m_cached_files.erase(it, m_cached_files.end());
} }
for (const auto& path : new_paths)
// Now that the previous loop has run, search_results only contains paths that
// aren't in m_cached_files, so we simply add all of them to m_cached_files.
for (const auto& path : search_results)
{ {
auto file = std::make_shared<GameListItem>(path); auto file = std::make_shared<GameListItem>(path);
if (file->IsValid()) if (file->IsValid())

View File

@ -125,7 +125,7 @@ private:
} m_image_indexes; } m_image_indexes;
// Actual backing GameListItems are maintained in a background thread and cached to file // Actual backing GameListItems are maintained in a background thread and cached to file
std::list<std::shared_ptr<GameListItem>> m_cached_files; std::vector<std::shared_ptr<GameListItem>> m_cached_files;
// Locks the list, not the contents // Locks the list, not the contents
std::mutex m_cache_mutex; std::mutex m_cache_mutex;
Core::TitleDatabase m_title_database; Core::TitleDatabase m_title_database;