| //===-- BackgroundRebuild.cpp - when to rebuild thei background index -----===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "index/BackgroundRebuild.h" |
| #include "Compiler.h" |
| #include "Headers.h" |
| #include "ParsedAST.h" |
| #include "SourceCode.h" |
| #include "Symbol.h" |
| #include "URI.h" |
| #include "index/FileIndex.h" |
| #include "index/IndexAction.h" |
| #include "index/MemIndex.h" |
| #include "index/Ref.h" |
| #include "index/Relation.h" |
| #include "index/Serialization.h" |
| #include "index/SymbolCollector.h" |
| #include "support/Logger.h" |
| #include "support/Path.h" |
| #include "support/Threading.h" |
| #include "support/Trace.h" |
| #include "clang/Basic/SourceLocation.h" |
| #include "clang/Basic/SourceManager.h" |
| #include "llvm/ADT/Hashing.h" |
| #include "llvm/ADT/STLExtras.h" |
| #include "llvm/ADT/ScopeExit.h" |
| #include "llvm/ADT/StringMap.h" |
| #include "llvm/ADT/StringRef.h" |
| #include "llvm/ADT/StringSet.h" |
| #include "llvm/Support/Error.h" |
| #include "llvm/Support/Threading.h" |
| |
| #include <atomic> |
| #include <chrono> |
| #include <condition_variable> |
| #include <memory> |
| #include <mutex> |
| #include <numeric> |
| #include <queue> |
| #include <random> |
| #include <string> |
| #include <thread> |
| |
| namespace clang { |
| namespace clangd { |
| |
| bool BackgroundIndexRebuilder::enoughTUsToRebuild() const { |
| if (!ActiveVersion) // never built |
| return IndexedTUs == TUsBeforeFirstBuild; // use low threshold |
| // rebuild if we've reached the (higher) threshold |
| return IndexedTUs >= IndexedTUsAtLastRebuild + TUsBeforeRebuild; |
| } |
| |
| void BackgroundIndexRebuilder::indexedTU() { |
| maybeRebuild("after indexing enough files", [this] { |
| ++IndexedTUs; |
| if (Loading) |
| return false; // rebuild once loading finishes |
| if (ActiveVersion != StartedVersion) // currently building |
| return false; // no urgency, avoid overlapping builds |
| return enoughTUsToRebuild(); |
| }); |
| } |
| |
| void BackgroundIndexRebuilder::idle() { |
| maybeRebuild("when background indexer is idle", [this] { |
| // rebuild if there's anything new in the index. |
| // (even if currently rebuilding! this ensures eventual completeness) |
| return IndexedTUs > IndexedTUsAtLastRebuild; |
| }); |
| } |
| |
| void BackgroundIndexRebuilder::startLoading() { |
| std::lock_guard<std::mutex> Lock(Mu); |
| if (!Loading) |
| LoadedShards = 0; |
| ++Loading; |
| } |
| void BackgroundIndexRebuilder::loadedShard(size_t ShardCount) { |
| std::lock_guard<std::mutex> Lock(Mu); |
| assert(Loading); |
| LoadedShards += ShardCount; |
| } |
| void BackgroundIndexRebuilder::doneLoading() { |
| maybeRebuild("after loading index from disk", [this] { |
| assert(Loading); |
| --Loading; |
| if (Loading) // was loading multiple batches concurrently |
| return false; // rebuild once the last batch is done. |
| // Rebuild if we loaded any shards, or if we stopped an indexedTU rebuild. |
| return LoadedShards > 0 || enoughTUsToRebuild(); |
| }); |
| } |
| |
| void BackgroundIndexRebuilder::shutdown() { |
| std::lock_guard<std::mutex> Lock(Mu); |
| ShouldStop = true; |
| } |
| |
| void BackgroundIndexRebuilder::maybeRebuild(const char *Reason, |
| std::function<bool()> Check) { |
| unsigned BuildVersion = 0; |
| { |
| std::lock_guard<std::mutex> Lock(Mu); |
| if (!ShouldStop && Check()) { |
| BuildVersion = ++StartedVersion; |
| IndexedTUsAtLastRebuild = IndexedTUs; |
| } |
| } |
| if (BuildVersion) { |
| std::unique_ptr<SymbolIndex> NewIndex; |
| { |
| vlog("BackgroundIndex: building version {0} {1}", BuildVersion, Reason); |
| trace::Span Tracer("RebuildBackgroundIndex"); |
| SPAN_ATTACH(Tracer, "reason", Reason); |
| NewIndex = Source->buildIndex(IndexType::Heavy, DuplicateHandling::Merge); |
| } |
| { |
| std::lock_guard<std::mutex> Lock(Mu); |
| // Guard against rebuild finishing in the wrong order. |
| if (BuildVersion > ActiveVersion) { |
| ActiveVersion = BuildVersion; |
| vlog("BackgroundIndex: serving version {0} ({1} bytes)", BuildVersion, |
| NewIndex->estimateMemoryUsage()); |
| Target->reset(std::move(NewIndex)); |
| } |
| } |
| } |
| } |
| |
| } // namespace clangd |
| } // namespace clang |