//===-- 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 #include #include #include #include #include #include #include #include #include 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 Lock(Mu); if (!Loading) LoadedShards = 0; ++Loading; } void BackgroundIndexRebuilder::loadedShard(size_t ShardCount) { std::lock_guard 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 Lock(Mu); ShouldStop = true; } void BackgroundIndexRebuilder::maybeRebuild(const char *Reason, std::function Check) { unsigned BuildVersion = 0; { std::lock_guard Lock(Mu); if (!ShouldStop && Check()) { BuildVersion = ++StartedVersion; IndexedTUsAtLastRebuild = IndexedTUs; } } if (BuildVersion) { std::unique_ptr 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 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