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