diff --git a/clang-tools-extra/clangd/index/remote/Client.cpp b/clang-tools-extra/clangd/index/remote/Client.cpp --- a/clang-tools-extra/clangd/index/remote/Client.cpp +++ b/clang-tools-extra/clangd/index/remote/Client.cpp @@ -6,10 +6,14 @@ // //===----------------------------------------------------------------------===// +#include #include #include "Client.h" #include "Service.grpc.pb.h" +#include "grpc/impl/codegen/connectivity_state.h" +#include "grpcpp/channel.h" +#include "grpcpp/impl/codegen/completion_queue.h" #include "index/Index.h" #include "marshalling/Marshalling.h" #include "support/Logger.h" @@ -19,6 +23,33 @@ #include "llvm/Support/Error.h" #include +#include +#include + +namespace llvm { +template <> struct format_provider { + static void format(const grpc_connectivity_state &State, raw_ostream &Stream, + StringRef Style) { + switch (State) { + case GRPC_CHANNEL_IDLE: + Stream << "GRPC_CHANNEL_IDLE"; + break; + case GRPC_CHANNEL_CONNECTING: + Stream << "GRPC_CHANNEL_CONNECTING"; + break; + case GRPC_CHANNEL_READY: + Stream << "GRPC_CHANNEL_READY"; + break; + case GRPC_CHANNEL_TRANSIENT_FAILURE: + Stream << "GRPC_CHANNEL_TRANSIENT_FAILURE"; + break; + case GRPC_CHANNEL_SHUTDOWN: + Stream << "GRPC_CHANNEL_SHUTDOWN"; + break; + } + } +}; +} // namespace llvm namespace clang { namespace clangd { @@ -80,6 +111,25 @@ /*LocalIndexRoot=*/ProjectRoot)), DeadlineWaitingTime(DeadlineTime) { assert(!ProjectRoot.empty()); + ChannelStatusWatcher = std::thread([&Channel]() { + grpc_connectivity_state Status = + Channel->GetState(/*try_to_connect=*/true); + static constexpr auto DeadlineWaitingTime = std::chrono::seconds(1); + log("Remote index connection status: {0}", Status); + while (!ClientShutdownRequested) { + if (Channel->WaitForStateChange(Status, + std::chrono::system_clock::now() + + DeadlineWaitingTime)) { + Status = Channel->GetState(/*try_to_connect=*/true); + log("Remote index connection status changed: {0}", Status); + } + } + }); + } + + ~IndexClient() { + ClientShutdownRequested = true; + ChannelStatusWatcher.join(); } void lookup(const clangd::LookupRequest &Request, @@ -121,15 +171,18 @@ std::unique_ptr ProtobufMarshaller; // Each request will be terminated if it takes too long. std::chrono::milliseconds DeadlineWaitingTime; + static std::atomic ClientShutdownRequested; + std::thread ChannelStatusWatcher; }; +std::atomic IndexClient::ClientShutdownRequested = {false}; + } // namespace std::unique_ptr getClient(llvm::StringRef Address, llvm::StringRef ProjectRoot) { const auto Channel = grpc::CreateChannel(Address.str(), grpc::InsecureChannelCredentials()); - Channel->GetState(true); return std::unique_ptr( new IndexClient(Channel, ProjectRoot)); }