Index: clangd/tool/ClangdMain.cpp =================================================================== --- clangd/tool/ClangdMain.cpp +++ clangd/tool/ClangdMain.cpp @@ -14,6 +14,8 @@ #include "index/SymbolYAML.h" #include "index/dex/DexIndex.h" #include "clang/Basic/Version.h" +#include "clang/Basic/Version.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" @@ -23,6 +25,7 @@ #include #include #include +#include #include #include @@ -39,22 +42,86 @@ enum class PCHStorageFlag { Disk, Memory }; -// Build an in-memory static index for global symbols from a YAML-format file. -// The size of global symbols should be relatively small, so that all symbols -// can be managed in memory. -std::unique_ptr buildStaticIndex(llvm::StringRef YamlSymbolFile) { - auto Buffer = llvm::MemoryBuffer::getFile(YamlSymbolFile); - if (!Buffer) { - llvm::errs() << "Can't open " << YamlSymbolFile << "\n"; - return nullptr; +// Loads the index asynchornously. This acts like an empty index before +// finishing loading and proxies index requests to the loaded index after +// loading. +class AsyncLoadIndex : public SymbolIndex { +public: + AsyncLoadIndex( + llvm::unique_function()> LoadIndex) + : AsyncLoad(runAsync(std::move(LoadIndex))) {} + + bool + fuzzyFind(const FuzzyFindRequest &Req, + llvm::function_ref Callback) const override { + if (!index()) + return false; // More + return index()->fuzzyFind(Req, Callback); + } + + void + lookup(const LookupRequest &Req, + llvm::function_ref Callback) const override { + if (!index()) + return; + return index()->lookup(Req, Callback); + } + + void findOccurrences(const OccurrencesRequest &Req, + llvm::function_ref + Callback) const override { + if (!index()) + return; + return index()->findOccurrences(Req, Callback); } - auto Slab = symbolsFromYAML(Buffer.get()->getBuffer()); - SymbolSlab::Builder SymsBuilder; - for (auto Sym : Slab) - SymsBuilder.insert(Sym); - return UseDex ? dex::DexIndex::build(std::move(SymsBuilder).build()) - : MemIndex::build(std::move(SymsBuilder).build()); + size_t estimateMemoryUsage() const override { return 0; } + +private: + const SymbolIndex *index() const { + if (Index) // Index doesn't change once initialized, so no need for mutex. + return Index.get(); + + std::lock_guard Lock(Mutex); + if (Index) // Make sure Index has not been set by the last mutex owner. + return Index.get(); + if (AsyncLoad.wait_for(std::chrono::seconds(0)) != + std::future_status::ready) + return nullptr; + + Index = AsyncLoad.get(); + return Index.get(); + } + mutable std::unique_ptr Index; + mutable std::future> AsyncLoad; + mutable std::mutex Mutex; +}; +// Asynchronously build an in-memory static index for global symbols from a +// YAML-format file. The size of global symbols should be relatively small, so +// that all symbols can be managed in memory. +std::unique_ptr buildStaticIndex(llvm::StringRef YamlSymbolFile) { + return llvm::make_unique( + [YamlSymbolFile]() -> std::unique_ptr { + trace::Span Tracer("Build static index"); + + auto Buffer = llvm::MemoryBuffer::getFile(YamlSymbolFile); + if (!Buffer) { + llvm::errs() << "Can't open " << YamlSymbolFile << "\n"; + return nullptr; + } + + SymbolSlab::Builder SymsBuilder; + { + trace::Span Tracer("YAML to symbols"); + auto Slab = symbolsFromYAML(Buffer.get()->getBuffer()); + for (auto Sym : Slab) + SymsBuilder.insert(Sym); + } + + trace::Span Build("Build index"); + return UseDex ? dex::DexIndex::build(std::move(SymsBuilder).build()) + : MemIndex::build(std::move(SymsBuilder).build()); + }); } } // namespace