2017-12-29 17:27:56 +00:00
|
|
|
#include "cache_manager.h"
|
2017-04-09 02:24:32 +00:00
|
|
|
|
2017-12-29 17:27:56 +00:00
|
|
|
#include "config.h"
|
2017-04-09 02:24:32 +00:00
|
|
|
#include "indexer.h"
|
2017-04-21 06:32:18 +00:00
|
|
|
#include "language_server_api.h"
|
2017-09-22 01:14:57 +00:00
|
|
|
#include "platform.h"
|
|
|
|
|
2017-08-15 07:46:21 +00:00
|
|
|
#include <loguru/loguru.hpp>
|
|
|
|
|
2017-04-09 02:24:32 +00:00
|
|
|
#include <algorithm>
|
2017-12-29 17:27:56 +00:00
|
|
|
#include <unordered_map>
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
// Manages loading caches from file paths for the indexer process.
|
|
|
|
struct RealCacheManager : ICacheManager {
|
|
|
|
explicit RealCacheManager(Config* config) : config_(config) {}
|
|
|
|
~RealCacheManager() override = default;
|
|
|
|
|
|
|
|
IndexFile* TryLoad(const std::string& path) override {
|
|
|
|
auto it = caches.find(path);
|
|
|
|
if (it != caches.end())
|
|
|
|
return it->second.get();
|
|
|
|
|
|
|
|
std::unique_ptr<IndexFile> cache = LoadCachedIndex(config_, path);
|
|
|
|
if (!cache)
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
caches[path] = std::move(cache);
|
|
|
|
return caches[path].get();
|
|
|
|
}
|
|
|
|
|
|
|
|
std::unique_ptr<IndexFile> TryTakeOrLoad(const std::string& path) override {
|
|
|
|
auto it = caches.find(path);
|
|
|
|
if (it != caches.end()) {
|
|
|
|
auto result = std::move(it->second);
|
|
|
|
caches.erase(it);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
return LoadCachedIndex(config_, path);
|
|
|
|
}
|
|
|
|
|
|
|
|
void IterateLoadedCaches(std::function<void(IndexFile*)> fn) override {
|
|
|
|
for (const auto& it : caches) {
|
|
|
|
assert(it.second);
|
|
|
|
fn(it.second.get());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::unordered_map<std::string, std::unique_ptr<IndexFile>> caches;
|
|
|
|
Config* config_;
|
|
|
|
};
|
|
|
|
|
|
|
|
// struct FakeCacheManager : ICacheManager {
|
|
|
|
// explicit FakeCacheManager(const std::vector<FakeCacheEntry>& entries) {
|
|
|
|
// assert(false && "TODO");
|
|
|
|
// }
|
|
|
|
// };
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
// static
|
|
|
|
std::unique_ptr<ICacheManager> ICacheManager::Make(Config* config) {
|
|
|
|
return MakeUnique<RealCacheManager>(config);
|
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
std::unique_ptr<ICacheManager> ICacheManager::MakeFake(
|
|
|
|
const std::vector<FakeCacheEntry>& entries) {
|
|
|
|
// return MakeUnique<FakeCacheManager>(entries);
|
|
|
|
assert(false && "TODO");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
ICacheManager::~ICacheManager() = default;
|
|
|
|
|
|
|
|
std::unique_ptr<IndexFile> ICacheManager::TakeOrLoad(const std::string& path) {
|
|
|
|
auto result = TryTakeOrLoad(path);
|
|
|
|
assert(result);
|
|
|
|
return result;
|
|
|
|
}
|
2017-04-09 02:24:32 +00:00
|
|
|
|
2017-04-18 02:59:48 +00:00
|
|
|
namespace {
|
|
|
|
|
2017-12-02 05:07:30 +00:00
|
|
|
std::string GetCachedBaseFileName(Config* config,
|
|
|
|
const std::string& source_file,
|
|
|
|
bool create_dir = false) {
|
|
|
|
assert(!config->cacheDirectory.empty());
|
|
|
|
std::string cache_file;
|
|
|
|
size_t len = config->projectRoot.size();
|
|
|
|
if (StartsWith(source_file, config->projectRoot)) {
|
|
|
|
cache_file = EscapeFileName(config->projectRoot) + '/' +
|
2017-12-05 16:24:37 +00:00
|
|
|
EscapeFileName(source_file.substr(len));
|
2017-12-02 05:07:30 +00:00
|
|
|
} else
|
|
|
|
cache_file = EscapeFileName(source_file);
|
|
|
|
|
|
|
|
return config->cacheDirectory + cache_file;
|
2017-04-09 02:24:32 +00:00
|
|
|
}
|
|
|
|
|
2017-04-18 02:59:48 +00:00
|
|
|
} // namespace
|
|
|
|
|
2017-05-21 19:51:15 +00:00
|
|
|
std::unique_ptr<IndexFile> LoadCachedIndex(Config* config,
|
|
|
|
const std::string& filename) {
|
2017-04-19 07:32:59 +00:00
|
|
|
if (!config->enableCacheRead)
|
|
|
|
return nullptr;
|
2017-04-11 07:29:36 +00:00
|
|
|
|
2017-12-05 16:24:37 +00:00
|
|
|
optional<std::string> file_content =
|
|
|
|
ReadContent(GetCachedBaseFileName(config, filename) + ".json");
|
2017-04-17 07:06:01 +00:00
|
|
|
if (!file_content)
|
2017-04-09 02:24:32 +00:00
|
|
|
return nullptr;
|
|
|
|
|
2017-08-17 02:06:28 +00:00
|
|
|
return Deserialize(filename, *file_content, IndexFile::kCurrentVersion);
|
2017-04-09 02:24:32 +00:00
|
|
|
}
|
|
|
|
|
2017-05-21 19:51:15 +00:00
|
|
|
optional<std::string> LoadCachedFileContents(Config* config,
|
2017-04-22 07:42:57 +00:00
|
|
|
const std::string& filename) {
|
2017-04-21 06:32:18 +00:00
|
|
|
if (!config->enableCacheRead)
|
2017-04-21 17:00:36 +00:00
|
|
|
return nullopt;
|
2017-04-21 06:32:18 +00:00
|
|
|
|
2017-12-02 05:07:30 +00:00
|
|
|
return ReadContent(GetCachedBaseFileName(config, filename));
|
2017-04-21 06:32:18 +00:00
|
|
|
}
|
|
|
|
|
2017-09-22 01:14:57 +00:00
|
|
|
void WriteToCache(Config* config, IndexFile& file) {
|
2017-04-19 07:32:59 +00:00
|
|
|
if (!config->enableCacheWrite)
|
|
|
|
return;
|
|
|
|
|
2017-12-05 16:24:37 +00:00
|
|
|
std::string cache_basename = GetCachedBaseFileName(config, file.path);
|
2017-08-15 07:46:21 +00:00
|
|
|
|
2017-09-22 07:39:59 +00:00
|
|
|
if (file.file_contents_.empty()) {
|
|
|
|
LOG_S(ERROR) << "No cached file contents; performing potentially stale "
|
|
|
|
<< "file-copy for " << file.path;
|
|
|
|
CopyFileTo(cache_basename, file.path);
|
|
|
|
} else {
|
|
|
|
std::ofstream cache_content;
|
|
|
|
cache_content.open(cache_basename);
|
|
|
|
assert(cache_content.good());
|
|
|
|
cache_content << file.file_contents_;
|
|
|
|
cache_content.close();
|
|
|
|
}
|
2017-04-21 06:32:18 +00:00
|
|
|
|
|
|
|
std::string indexed_content = Serialize(file);
|
2017-04-09 02:24:32 +00:00
|
|
|
std::ofstream cache;
|
2017-04-21 06:32:18 +00:00
|
|
|
cache.open(cache_basename + ".json");
|
2017-04-09 02:24:32 +00:00
|
|
|
assert(cache.good());
|
|
|
|
cache << indexed_content;
|
|
|
|
cache.close();
|
2017-04-19 00:05:14 +00:00
|
|
|
}
|