Speed up archive caching

This is particularly significant for large Data directories.
This commit is contained in:
Oliver Hamlet
2020-07-11 18:29:02 +01:00
parent 2bdb847e6f
commit 9900860802
5 changed files with 22 additions and 43 deletions
+10 -8
View File
@@ -153,7 +153,6 @@ void Game::LoadPlugins(const std::vector<std::string>& plugins,
// Clear the existing plugin and archive caches.
cache_->ClearCachedPlugins();
cache_->ClearCachedArchivePaths();
// Search for and cache archives.
CacheArchives();
@@ -243,17 +242,20 @@ void Game::SetLoadOrder(const std::vector<std::string>& loadOrder) {
void Game::CacheArchives() {
const auto archiveFileExtension = GetArchiveFileExtension(Type());
std::set<std::filesystem::path> archivePaths;
for (std::filesystem::directory_iterator it(DataPath());
it != std::filesystem::directory_iterator();
++it) {
// Check if the path is an archive by checking if replacing its
// file extension with the archive extension resolves to the same file.
// Could use boost::iends_with, but it's less obvious here that the
// test string is ASCII-only.
if (loot::equivalent(it->path(),
replaceExtension(it->path(), archiveFileExtension))) {
cache_->CacheArchivePath(it->path());
// This is only correct for ASCII strings, but that's all that
// GetArchiveFileExtension() can return. It's a lot faster than the more
// generally-correct approach of testing file path equivalence when
// there are a lot of entries in DataPath().
if (it->is_regular_file() &&
boost::iends_with(it->path().u8string(), archiveFileExtension)) {
archivePaths.insert(it->path());
}
}
cache_->CacheArchivePaths(std::move(archivePaths));
}
}
+5 -15
View File
@@ -36,8 +36,7 @@ using std::string;
namespace loot {
GameCache::GameCache() {}
GameCache::GameCache(const GameCache& cache) :
plugins_(cache.plugins_) {}
GameCache::GameCache(const GameCache& cache) : plugins_(cache.plugins_) {}
GameCache& GameCache::operator=(const GameCache& cache) {
if (&cache != this) {
@@ -78,20 +77,17 @@ void GameCache::AddPlugin(const Plugin&& plugin) {
if (it != end(plugins_))
plugins_.erase(it);
plugins_.emplace(normalizedName,
std::make_shared<Plugin>(std::move(plugin)));
plugins_.emplace(normalizedName, std::make_shared<Plugin>(std::move(plugin)));
}
std::set<std::filesystem::path> GameCache::GetArchivePaths() const
{
std::set<std::filesystem::path> GameCache::GetArchivePaths() const {
return archivePaths_;
}
void GameCache::CacheArchivePath(const std::filesystem::path& path)
{
void GameCache::CacheArchivePaths(std::set<std::filesystem::path>&& paths) {
lock_guard<mutex> lock(mutex_);
archivePaths_.insert(path);
archivePaths_ = paths;
}
void GameCache::ClearCachedPlugins() {
@@ -99,10 +95,4 @@ void GameCache::ClearCachedPlugins() {
plugins_.clear();
}
void GameCache::ClearCachedArchivePaths() {
lock_guard<mutex> guard(mutex_);
archivePaths_.clear();
}
}
+1 -2
View File
@@ -44,10 +44,9 @@ public:
void AddPlugin(const Plugin&& plugin);
std::set<std::filesystem::path> GetArchivePaths() const;
void CacheArchivePath(const std::filesystem::path& path);
void CacheArchivePaths(std::set<std::filesystem::path>&& paths);
void ClearCachedPlugins();
void ClearCachedArchivePaths();
private:
std::unordered_map<std::string, std::shared_ptr<const Plugin>> plugins_;
+2 -14
View File
@@ -113,8 +113,8 @@ TEST_P(GameCacheTest,
TEST_P(GameCacheTest,
gettingArchivePathsShouldReturnASetOfPathsIfPathsHaveBeenCached) {
cache_.CacheArchivePath(game_.DataPath() / blankEsm);
cache_.CacheArchivePath(game_.DataPath() / blankMasterDependentEsm);
cache_.CacheArchivePaths({game_.DataPath() / blankEsm,
game_.DataPath() / blankMasterDependentEsm});
auto expected = std::set<std::filesystem::path>({
game_.DataPath() / blankEsm,
@@ -137,18 +137,6 @@ TEST_P(GameCacheTest, clearingCachedPluginsShouldClearAnyCachedPlugins) {
EXPECT_TRUE(cache_.GetPlugins().empty());
}
TEST_P(GameCacheTest,
clearingCachedArchivePathsShouldNotThrowIfNoPathsAreCached) {
EXPECT_NO_THROW(cache_.GetArchivePaths());
}
TEST_P(GameCacheTest, clearingCachedArchivePathsShouldClearAnyCachedPaths) {
cache_.CacheArchivePath(game_.DataPath() / blankEsm);
cache_.ClearCachedArchivePaths();
EXPECT_TRUE(cache_.GetArchivePaths().empty());
}
}
}
+4 -4
View File
@@ -91,10 +91,10 @@ protected:
out.open(nonAsciiPrefixArchivePath);
out.close();
game_.GetCache()->CacheArchivePath(dataPath / blankArchive);
game_.GetCache()->CacheArchivePath(dataPath / blankSuffixArchive);
game_.GetCache()->CacheArchivePath(dataPath / nonAsciiArchivePath);
game_.GetCache()->CacheArchivePath(dataPath / nonAsciiPrefixArchivePath);
game_.GetCache()->CacheArchivePaths({dataPath / blankArchive,
dataPath / blankSuffixArchive,
dataPath / nonAsciiArchivePath,
dataPath / nonAsciiPrefixArchivePath});
}
uintmax_t getGhostedPluginFileSize() {