114 lines · cpp
1//===-- BackgroundRebuild.cpp - when to rebuild the background index ------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "index/BackgroundRebuild.h"10#include "index/FileIndex.h"11#include "support/Logger.h"12#include "support/Trace.h"13 14#include <atomic>15#include <chrono>16#include <condition_variable>17#include <memory>18#include <mutex>19#include <numeric>20#include <queue>21#include <random>22#include <string>23#include <thread>24 25namespace clang {26namespace clangd {27 28bool BackgroundIndexRebuilder::enoughTUsToRebuild() const {29 if (!ActiveVersion) // never built30 return IndexedTUs == TUsBeforeFirstBuild; // use low threshold31 // rebuild if we've reached the (higher) threshold32 return IndexedTUs >= IndexedTUsAtLastRebuild + TUsBeforeRebuild;33}34 35void BackgroundIndexRebuilder::indexedTU() {36 maybeRebuild("after indexing enough files", [this] {37 ++IndexedTUs;38 if (Loading)39 return false; // rebuild once loading finishes40 if (ActiveVersion != StartedVersion) // currently building41 return false; // no urgency, avoid overlapping builds42 return enoughTUsToRebuild();43 });44}45 46void BackgroundIndexRebuilder::idle() {47 maybeRebuild("when background indexer is idle", [this] {48 // rebuild if there's anything new in the index.49 // (even if currently rebuilding! this ensures eventual completeness)50 return IndexedTUs > IndexedTUsAtLastRebuild;51 });52}53 54void BackgroundIndexRebuilder::startLoading() {55 std::lock_guard<std::mutex> Lock(Mu);56 if (!Loading)57 LoadedShards = 0;58 ++Loading;59}60void BackgroundIndexRebuilder::loadedShard(size_t ShardCount) {61 std::lock_guard<std::mutex> Lock(Mu);62 assert(Loading);63 LoadedShards += ShardCount;64}65void BackgroundIndexRebuilder::doneLoading() {66 maybeRebuild("after loading index from disk", [this] {67 assert(Loading);68 --Loading;69 if (Loading) // was loading multiple batches concurrently70 return false; // rebuild once the last batch is done.71 // Rebuild if we loaded any shards, or if we stopped an indexedTU rebuild.72 return LoadedShards > 0 || enoughTUsToRebuild();73 });74}75 76void BackgroundIndexRebuilder::shutdown() {77 std::lock_guard<std::mutex> Lock(Mu);78 ShouldStop = true;79}80 81void BackgroundIndexRebuilder::maybeRebuild(const char *Reason,82 std::function<bool()> Check) {83 unsigned BuildVersion = 0;84 {85 std::lock_guard<std::mutex> Lock(Mu);86 if (!ShouldStop && Check()) {87 BuildVersion = ++StartedVersion;88 IndexedTUsAtLastRebuild = IndexedTUs;89 }90 }91 if (BuildVersion) {92 std::unique_ptr<SymbolIndex> NewIndex;93 {94 vlog("BackgroundIndex: building version {0} {1}", BuildVersion, Reason);95 trace::Span Tracer("RebuildBackgroundIndex");96 SPAN_ATTACH(Tracer, "reason", Reason);97 NewIndex = Source->buildIndex(IndexType::Heavy, DuplicateHandling::Merge);98 }99 {100 std::lock_guard<std::mutex> Lock(Mu);101 // Guard against rebuild finishing in the wrong order.102 if (BuildVersion > ActiveVersion) {103 ActiveVersion = BuildVersion;104 vlog("BackgroundIndex: serving version {0} ({1} bytes)", BuildVersion,105 NewIndex->estimateMemoryUsage());106 Target->reset(std::move(NewIndex));107 }108 }109 }110}111 112} // namespace clangd113} // namespace clang114