TerraSync: use an unordered_map for the hash cache

Linear-scan is a bit slow in debug builds, for the large Airports/ tree;
switch to an unordered_map.

Will back-port to the LTS once tested a bit more.
This commit is contained in:
James Turner 2020-10-29 23:13:10 +00:00 committed by James Turner
parent 3ff3bd0a6c
commit 96bafef3f3
2 changed files with 17 additions and 23 deletions

View File

@ -986,25 +986,16 @@ HTTPRepository::failure() const
return r; return r;
} }
class HashEntryWithPath
{
public:
HashEntryWithPath(const SGPath& p) : path(p.utf8Str()) {}
bool operator()(const HTTPRepoPrivate::HashCacheEntry& entry) const
{ return entry.filePath == path; }
private:
std::string path;
};
std::string HTTPRepoPrivate::hashForPath(const SGPath& p) std::string HTTPRepoPrivate::hashForPath(const SGPath& p)
{ {
HashCache::iterator it = std::find_if(hashes.begin(), hashes.end(), HashEntryWithPath(p)); const auto ps = p.utf8Str();
auto it = hashes.find(ps);
if (it != hashes.end()) { if (it != hashes.end()) {
const auto& entry = it->second;
// ensure data on disk hasn't changed. // ensure data on disk hasn't changed.
// we could also use the file type here if we were paranoid // we could also use the file type here if we were paranoid
if ((p.sizeInBytes() == it->lengthBytes) && (p.modTime() == it->modTime)) { if ((p.sizeInBytes() == entry.lengthBytes) && (p.modTime() == entry.modTime)) {
return it->hashHex; return entry.hashHex;
} }
// entry in the cache, but it's stale so remove and fall through // entry in the cache, but it's stale so remove and fall through
@ -1049,7 +1040,8 @@ HTTPRepository::failure() const
void HTTPRepoPrivate::updatedFileContents(const SGPath& p, const std::string& newHash) void HTTPRepoPrivate::updatedFileContents(const SGPath& p, const std::string& newHash)
{ {
// remove the existing entry // remove the existing entry
auto it = std::find_if(hashes.begin(), hashes.end(), HashEntryWithPath(p)); const auto ps = p.utf8Str();
auto it = hashes.find(ps);
if (it != hashes.end()) { if (it != hashes.end()) {
hashes.erase(it); hashes.erase(it);
++hashCacheDirty; ++hashCacheDirty;
@ -1065,11 +1057,11 @@ HTTPRepository::failure() const
p2.set_cached(true); p2.set_cached(true);
HashCacheEntry entry; HashCacheEntry entry;
entry.filePath = p.utf8Str(); entry.filePath = ps;
entry.hashHex = newHash; entry.hashHex = newHash;
entry.modTime = p2.modTime(); entry.modTime = p2.modTime();
entry.lengthBytes = p2.sizeInBytes(); entry.lengthBytes = p2.sizeInBytes();
hashes.push_back(entry); hashes.insert(std::make_pair(ps, entry));
++hashCacheDirty ; ++hashCacheDirty ;
} }
@ -1083,10 +1075,11 @@ HTTPRepository::failure() const
SGPath cachePath = basePath; SGPath cachePath = basePath;
cachePath.append(".hashes"); cachePath.append(".hashes");
sg_ofstream stream(cachePath, std::ios::out | std::ios::trunc | std::ios::binary); sg_ofstream stream(cachePath, std::ios::out | std::ios::trunc | std::ios::binary);
HashCache::const_iterator it; for (const auto& e : hashes) {
for (it = hashes.begin(); it != hashes.end(); ++it) { const auto& entry = e.second;
stream << it->filePath << "*" << it->modTime << "*"
<< it->lengthBytes << "*" << it->hashHex << "\n"; stream << entry.filePath << "*" << entry.modTime << "*"
<< entry.lengthBytes << "*" << entry.hashHex << "\n";
} }
stream.close(); stream.close();
hashCacheDirty = 0; hashCacheDirty = 0;
@ -1130,7 +1123,7 @@ HTTPRepository::failure() const
entry.hashHex = hashData; entry.hashHex = hashData;
entry.modTime = strtol(timeData.c_str(), NULL, 10); entry.modTime = strtol(timeData.c_str(), NULL, 10);
entry.lengthBytes = strtol(sizeData.c_str(), NULL, 10); entry.lengthBytes = strtol(sizeData.c_str(), NULL, 10);
hashes.push_back(entry); hashes.insert(std::make_pair(entry.filePath, entry));
} }
} }

View File

@ -21,6 +21,7 @@
#include <memory> #include <memory>
#include <string> #include <string>
#include <unordered_map>
#include <simgear/io/HTTPClient.hxx> #include <simgear/io/HTTPClient.hxx>
#include <simgear/misc/sg_path.hxx> #include <simgear/misc/sg_path.hxx>
@ -59,7 +60,7 @@ public:
std::string hashHex; std::string hashHex;
}; };
typedef std::vector<HashCacheEntry> HashCache; using HashCache = std::unordered_map<std::string, HashCacheEntry>;
HashCache hashes; HashCache hashes;
int hashCacheDirty = 0; int hashCacheDirty = 0;