diff --git a/clang-tools-extra/clangd/index/remote/server/Server.cpp b/clang-tools-extra/clangd/index/remote/server/Server.cpp --- a/clang-tools-extra/clangd/index/remote/server/Server.cpp +++ b/clang-tools-extra/clangd/index/remote/server/Server.cpp @@ -14,13 +14,18 @@ #include "support/Logger.h" #include "support/Trace.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/Chrono.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Error.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" #include "llvm/Support/Signals.h" +#include #include #include +#include +#include #include "Index.grpc.pb.h" @@ -69,8 +74,7 @@ class RemoteIndexServer final : public SymbolIndex::Service { public: - RemoteIndexServer(std::unique_ptr Index, - llvm::StringRef IndexRoot) + RemoteIndexServer(clangd::SwapIndex *Index, llvm::StringRef IndexRoot) : Index(std::move(Index)) { llvm::SmallString<256> NativePath = IndexRoot; llvm::sys::path::native(NativePath); @@ -79,6 +83,8 @@ /*LocalIndexRoot=*/"")); } + clangd::SwapIndex *Index; + private: grpc::Status Lookup(grpc::ServerContext *Context, const LookupRequest *Request, @@ -210,21 +216,52 @@ return grpc::Status::OK; } - std::unique_ptr Index; std::unique_ptr ProtobufMarshaller; }; -void runServer(std::unique_ptr Index, - const std::string &ServerAddress) { - RemoteIndexServer Service(std::move(Index), IndexRoot); +// Detect changes in \p IndexPath file and load new versions of the index +// whenever they become available. +void hotReload(clangd::SwapIndex **Index, llvm::StringRef IndexPath) { + llvm::sys::TimePoint<> LastModificationTime = + std::chrono::system_clock::now(); + for (;; std::this_thread::sleep_for(std::chrono::seconds(90))) { + llvm::sys::fs::file_status Status; + const auto EC = llvm::sys::fs::status(IndexPath, Status, /*Follow=*/true); + if (EC) + continue; + const auto NewModificationTime = Status.getLastModificationTime(); + // Current index is newer than the one before: no reload is needed. + if (NewModificationTime <= LastModificationTime) + continue; + vlog("Found new index version: existing index was modified at {0}, new " + "index was modified at {1}. Attempting to reload.", + LastModificationTime, NewModificationTime); + std::unique_ptr NewIndex = openIndex(IndexPath); + if (!NewIndex) { + vlog("Failed to load new index. Old index will be served."); + continue; + } + (*Index)->reset(std::move(NewIndex)); + log("New index version loaded. Last modification time: {0}.", + NewModificationTime); + LastModificationTime = NewModificationTime; + } +} + +void runServer(std::unique_ptr Index, + llvm::StringRef ServerAddress, llvm::StringRef IndexPath) { + RemoteIndexServer Service(Index.get(), IndexRoot); grpc::EnableDefaultHealthCheckService(true); grpc::ServerBuilder Builder; - Builder.AddListeningPort(ServerAddress, grpc::InsecureServerCredentials()); + Builder.AddListeningPort(ServerAddress.str(), + grpc::InsecureServerCredentials()); Builder.RegisterService(&Service); std::unique_ptr Server(Builder.BuildAndStart()); log("Server listening on {0}", ServerAddress); + std::thread HotReloadThread(hotReload, &Service.Index, IndexPath); + Server->Wait(); } @@ -273,12 +310,13 @@ if (Tracer) TracingSession.emplace(*Tracer); - std::unique_ptr Index = openIndex(IndexPath); + std::unique_ptr Index( + new clang::clangd::SwapIndex(openIndex(IndexPath))); if (!Index) { llvm::errs() << "Failed to open the index.\n"; return -1; } - runServer(std::move(Index), ServerAddress); + runServer(std::move(Index), ServerAddress, IndexPath); }