1//===-- BackgroundRebuild.cpp - when to rebuild thei 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-exception
6//
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 built
30 return IndexedTUs == TUsBeforeFirstBuild; // use low threshold
31 // rebuild if we've reached the (higher) threshold
32 return IndexedTUs >= IndexedTUsAtLastRebuild + TUsBeforeRebuild;
33}
34
35void BackgroundIndexRebuilder::indexedTU() {
36 maybeRebuild(Reason: "after indexing enough files", Check: [this] {
37 ++IndexedTUs;
38 if (Loading)
39 return false; // rebuild once loading finishes
40 if (ActiveVersion != StartedVersion) // currently building
41 return false; // no urgency, avoid overlapping builds
42 return enoughTUsToRebuild();
43 });
44}
45
46void BackgroundIndexRebuilder::idle() {
47 maybeRebuild(Reason: "when background indexer is idle", Check: [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(Reason: "after loading index from disk", Check: [this] {
67 assert(Loading);
68 --Loading;
69 if (Loading) // was loading multiple batches concurrently
70 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(Fmt: "BackgroundIndex: building version {0} {1}", Vals&: BuildVersion, Vals&: Reason);
95 trace::Span Tracer("RebuildBackgroundIndex");
96 SPAN_ATTACH(Tracer, "reason", Reason);
97 NewIndex = Source->buildIndex(IndexType::Heavy, DuplicateHandle: 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(Fmt: "BackgroundIndex: serving version {0} ({1} bytes)", Vals&: BuildVersion,
105 Vals: NewIndex->estimateMemoryUsage());
106 Target->reset(std::move(NewIndex));
107 }
108 }
109 }
110}
111
112} // namespace clangd
113} // namespace clang
114

source code of clang-tools-extra/clangd/index/BackgroundRebuild.cpp