1 #include "cache_manager.h"
2
3 #include "config.h"
4 #include "indexer.h"
5 #include "lsp.h"
6 #include "platform.h"
7
8 #include <loguru/loguru.hpp>
9
10 #include <algorithm>
11 #include <unordered_map>
12
13 namespace {
14
15 // Manages loading caches from file paths for the indexer process.
16 struct RealCacheManager : ICacheManager {
RealCacheManager__anonc28c45fa0111::RealCacheManager17 explicit RealCacheManager() {}
18 ~RealCacheManager() override = default;
19
WriteToCache__anonc28c45fa0111::RealCacheManager20 void WriteToCache(IndexFile& file) override {
21 std::string cache_path = GetCachePath(file.path);
22 WriteToFile(cache_path, file.file_contents);
23
24 std::string indexed_content = Serialize(g_config->cacheFormat, file);
25 WriteToFile(AppendSerializationFormat(cache_path), indexed_content);
26 }
27
LoadCachedFileContents__anonc28c45fa0111::RealCacheManager28 optional<std::string> LoadCachedFileContents(
29 const std::string& path) override {
30 return ReadContent(GetCachePath(path));
31 }
32
RawCacheLoad__anonc28c45fa0111::RealCacheManager33 std::unique_ptr<IndexFile> RawCacheLoad(const std::string& path) override {
34 std::string cache_path = GetCachePath(path);
35 optional<std::string> file_content = ReadContent(cache_path);
36 optional<std::string> serialized_indexed_content =
37 ReadContent(AppendSerializationFormat(cache_path));
38 if (!file_content || !serialized_indexed_content)
39 return nullptr;
40
41 return Deserialize(g_config->cacheFormat, path, *serialized_indexed_content,
42 *file_content, IndexFile::kMajorVersion);
43 }
44
GetCachePath__anonc28c45fa0111::RealCacheManager45 std::string GetCachePath(const std::string& source_file) {
46 assert(!g_config->cacheDirectory.empty());
47 std::string cache_file;
48 size_t len = g_config->projectRoot.size();
49 if (StartsWith(source_file, g_config->projectRoot)) {
50 cache_file = EscapeFileName(g_config->projectRoot) + '/' +
51 EscapeFileName(source_file.substr(len));
52 } else {
53 cache_file = '@' + EscapeFileName(g_config->projectRoot) + '/' +
54 EscapeFileName(source_file);
55 }
56
57 return g_config->cacheDirectory + cache_file;
58 }
59
AppendSerializationFormat__anonc28c45fa0111::RealCacheManager60 std::string AppendSerializationFormat(const std::string& base) {
61 switch (g_config->cacheFormat) {
62 case SerializeFormat::Json:
63 return base + ".json";
64 case SerializeFormat::MessagePack:
65 return base + ".mpack";
66 }
67 assert(false);
68 return ".json";
69 }
70 };
71
72 struct FakeCacheManager : ICacheManager {
FakeCacheManager__anonc28c45fa0111::FakeCacheManager73 explicit FakeCacheManager(const std::vector<FakeCacheEntry>& entries)
74 : entries_(entries) {}
75
76 // TODO: should we allow tests to write cache files?
WriteToCache__anonc28c45fa0111::FakeCacheManager77 void WriteToCache(IndexFile& file) override {}
78
LoadCachedFileContents__anonc28c45fa0111::FakeCacheManager79 optional<std::string> LoadCachedFileContents(
80 const std::string& path) override {
81 for (const FakeCacheEntry& entry : entries_) {
82 if (entry.path == path) {
83 return entry.content;
84 }
85 }
86
87 return nullopt;
88 }
89
RawCacheLoad__anonc28c45fa0111::FakeCacheManager90 std::unique_ptr<IndexFile> RawCacheLoad(const std::string& path) override {
91 for (const FakeCacheEntry& entry : entries_) {
92 if (entry.path == path) {
93 return Deserialize(SerializeFormat::Json, path, entry.json, "<empty>",
94 nullopt);
95 }
96 }
97
98 return nullptr;
99 }
100
101 std::vector<FakeCacheEntry> entries_;
102 };
103
104 } // namespace
105
106 // static
Make()107 std::shared_ptr<ICacheManager> ICacheManager::Make() {
108 return std::make_shared<RealCacheManager>();
109 }
110
111 // static
MakeFake(const std::vector<FakeCacheEntry> & entries)112 std::shared_ptr<ICacheManager> ICacheManager::MakeFake(
113 const std::vector<FakeCacheEntry>& entries) {
114 return std::make_shared<FakeCacheManager>(entries);
115 }
116
117 ICacheManager::~ICacheManager() = default;
118
TryLoad(const std::string & path)119 IndexFile* ICacheManager::TryLoad(const std::string& path) {
120 auto it = caches_.find(path);
121 if (it != caches_.end())
122 return it->second.get();
123
124 std::unique_ptr<IndexFile> cache = RawCacheLoad(path);
125 if (!cache)
126 return nullptr;
127
128 caches_[path] = std::move(cache);
129 return caches_[path].get();
130 }
131
TryTakeOrLoad(const std::string & path)132 std::unique_ptr<IndexFile> ICacheManager::TryTakeOrLoad(
133 const std::string& path) {
134 auto it = caches_.find(path);
135 if (it != caches_.end()) {
136 auto result = std::move(it->second);
137 caches_.erase(it);
138 return result;
139 }
140
141 return RawCacheLoad(path);
142 }
143
TakeOrLoad(const std::string & path)144 std::unique_ptr<IndexFile> ICacheManager::TakeOrLoad(const std::string& path) {
145 auto result = TryTakeOrLoad(path);
146 assert(result);
147 return result;
148 }
149
IterateLoadedCaches(std::function<void (IndexFile *)> fn)150 void ICacheManager::IterateLoadedCaches(std::function<void(IndexFile*)> fn) {
151 for (const auto& cache : caches_) {
152 assert(cache.second);
153 fn(cache.second.get());
154 }
155 }
156