| 1 | //===-- BackgroundIndexLoader.cpp - ---------------------------------------===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | |
| 9 | #include "index/BackgroundIndexLoader.h" |
| 10 | #include "GlobalCompilationDatabase.h" |
| 11 | #include "index/Background.h" |
| 12 | #include "support/Logger.h" |
| 13 | #include "support/Path.h" |
| 14 | #include "llvm/ADT/StringMap.h" |
| 15 | #include "llvm/Support/Path.h" |
| 16 | #include <string> |
| 17 | #include <utility> |
| 18 | #include <vector> |
| 19 | |
| 20 | namespace clang { |
| 21 | namespace clangd { |
| 22 | namespace { |
| 23 | |
| 24 | /// A helper class to cache BackgroundIndexStorage operations and keep the |
| 25 | /// inverse dependency mapping. |
| 26 | class BackgroundIndexLoader { |
| 27 | public: |
| 28 | BackgroundIndexLoader(BackgroundIndexStorage::Factory &IndexStorageFactory) |
| 29 | : IndexStorageFactory(IndexStorageFactory) {} |
| 30 | /// Load the shards for \p MainFile and all of its dependencies. |
| 31 | void load(PathRef MainFile); |
| 32 | |
| 33 | /// Consumes the loader and returns all shards. |
| 34 | std::vector<LoadedShard> takeResult() &&; |
| 35 | |
| 36 | private: |
| 37 | /// Returns the Shard for \p StartSourceFile from cache or loads it from \p |
| 38 | /// Storage. Also returns paths for dependencies of \p StartSourceFile if it |
| 39 | /// wasn't cached yet. |
| 40 | std::pair<const LoadedShard &, std::vector<Path>> |
| 41 | loadShard(PathRef StartSourceFile, PathRef DependentTU); |
| 42 | |
| 43 | /// Cache for Storage lookups. |
| 44 | llvm::StringMap<LoadedShard> LoadedShards; |
| 45 | |
| 46 | BackgroundIndexStorage::Factory &IndexStorageFactory; |
| 47 | }; |
| 48 | |
| 49 | std::pair<const LoadedShard &, std::vector<Path>> |
| 50 | BackgroundIndexLoader::loadShard(PathRef StartSourceFile, PathRef DependentTU) { |
| 51 | auto It = LoadedShards.try_emplace(Key: StartSourceFile); |
| 52 | LoadedShard &LS = It.first->getValue(); |
| 53 | std::vector<Path> Edges = {}; |
| 54 | // Return the cached shard. |
| 55 | if (!It.second) |
| 56 | return {LS, Edges}; |
| 57 | |
| 58 | LS.AbsolutePath = StartSourceFile.str(); |
| 59 | LS.DependentTU = std::string(DependentTU); |
| 60 | BackgroundIndexStorage *Storage = IndexStorageFactory(LS.AbsolutePath); |
| 61 | auto Shard = Storage->loadShard(ShardIdentifier: StartSourceFile); |
| 62 | if (!Shard || !Shard->Sources) { |
| 63 | vlog(Fmt: "Failed to load shard: {0}" , Vals&: StartSourceFile); |
| 64 | return {LS, Edges}; |
| 65 | } |
| 66 | |
| 67 | LS.Shard = std::move(Shard); |
| 68 | for (const auto &It : *LS.Shard->Sources) { |
| 69 | auto AbsPath = URI::resolve(FileURI: It.getKey(), HintPath: StartSourceFile); |
| 70 | if (!AbsPath) { |
| 71 | elog(Fmt: "Failed to resolve URI: {0}" , Vals: AbsPath.takeError()); |
| 72 | continue; |
| 73 | } |
| 74 | // A shard contains only edges for non main-file sources. |
| 75 | if (*AbsPath != StartSourceFile) { |
| 76 | Edges.push_back(x: *AbsPath); |
| 77 | continue; |
| 78 | } |
| 79 | |
| 80 | // Fill in shard metadata. |
| 81 | const IncludeGraphNode &IGN = It.getValue(); |
| 82 | LS.Digest = IGN.Digest; |
| 83 | LS.CountReferences = IGN.Flags & IncludeGraphNode::SourceFlag::IsTU; |
| 84 | LS.HadErrors = IGN.Flags & IncludeGraphNode::SourceFlag::HadErrors; |
| 85 | } |
| 86 | assert(LS.Digest != FileDigest{{0}} && "Digest is empty?" ); |
| 87 | return {LS, Edges}; |
| 88 | } |
| 89 | |
| 90 | void BackgroundIndexLoader::load(PathRef MainFile) { |
| 91 | llvm::StringSet<> InQueue; |
| 92 | // Following containers points to strings inside InQueue. |
| 93 | std::queue<PathRef> ToVisit; |
| 94 | InQueue.insert(key: MainFile); |
| 95 | ToVisit.push(x: MainFile); |
| 96 | |
| 97 | while (!ToVisit.empty()) { |
| 98 | PathRef SourceFile = ToVisit.front(); |
| 99 | ToVisit.pop(); |
| 100 | |
| 101 | auto ShardAndEdges = loadShard(StartSourceFile: SourceFile, DependentTU: MainFile); |
| 102 | for (PathRef Edge : ShardAndEdges.second) { |
| 103 | auto It = InQueue.insert(key: Edge); |
| 104 | if (It.second) |
| 105 | ToVisit.push(x: It.first->getKey()); |
| 106 | } |
| 107 | } |
| 108 | } |
| 109 | |
| 110 | std::vector<LoadedShard> BackgroundIndexLoader::takeResult() && { |
| 111 | std::vector<LoadedShard> Result; |
| 112 | Result.reserve(n: LoadedShards.size()); |
| 113 | for (auto &It : LoadedShards) |
| 114 | Result.push_back(x: std::move(It.getValue())); |
| 115 | return Result; |
| 116 | } |
| 117 | } // namespace |
| 118 | |
| 119 | std::vector<LoadedShard> |
| 120 | loadIndexShards(llvm::ArrayRef<Path> MainFiles, |
| 121 | BackgroundIndexStorage::Factory &IndexStorageFactory, |
| 122 | const GlobalCompilationDatabase &CDB) { |
| 123 | BackgroundIndexLoader Loader(IndexStorageFactory); |
| 124 | for (llvm::StringRef MainFile : MainFiles) { |
| 125 | assert(llvm::sys::path::is_absolute(MainFile)); |
| 126 | Loader.load(MainFile); |
| 127 | } |
| 128 | return std::move(Loader).takeResult(); |
| 129 | } |
| 130 | |
| 131 | } // namespace clangd |
| 132 | } // namespace clang |
| 133 | |