ccls/src/cache_manager.cc

147 lines
4.0 KiB
C++
Raw Normal View History

#include "cache_manager.h"
2017-04-09 02:24:32 +00:00
#include "config.h"
2017-04-09 02:24:32 +00:00
#include "indexer.h"
#include "language_server_api.h"
2017-09-22 01:14:57 +00:00
#include "platform.h"
#include <loguru/loguru.hpp>
2017-04-09 02:24:32 +00:00
#include <algorithm>
#include <unordered_map>
namespace {
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) + '/' +
EscapeFileName(source_file.substr(len));
} else
cache_file = EscapeFileName(source_file);
return config->cacheDirectory + cache_file;
}
std::string GetCacheFileName(Config* config, const std::string& base) {
switch (config->cacheFormat) {
case SerializeFormat::Json:
return base + "json";
case SerializeFormat::MessagePack:
return base + "mpack";
}
}
std::unique_ptr<IndexFile> LoadCachedIndex(Config* config,
const std::string& filename) {
if (!config->enableCacheRead)
return nullptr;
optional<std::string> file_content = ReadContent(
GetCacheFileName(config, GetCachedBaseFileName(config, filename)));
if (!file_content)
return nullptr;
return Deserialize(config->cacheFormat, filename, *file_content,
IndexFile::kCurrentVersion);
}
// 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);
}
optional<std::string> LoadCachedFileContents(
const std::string& filename) override {
if (!config_->enableCacheRead)
return nullopt;
return ReadContent(GetCachedBaseFileName(config_, filename));
}
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-09-22 01:14:57 +00:00
void WriteToCache(Config* config, IndexFile& file) {
if (!config->enableCacheWrite)
return;
2017-12-05 16:24:37 +00:00
std::string cache_basename = GetCachedBaseFileName(config, file.path);
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 {
WriteToFile(cache_basename, file.file_contents_);
}
std::string indexed_content = Serialize(file);
WriteToFile(GetCacheFileName(config, cache_basename), indexed_content);
2017-04-19 00:05:14 +00:00
}