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 | |
25 | namespace clang { |
26 | namespace clangd { |
27 | |
28 | bool 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 | |
35 | void 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 | |
46 | void 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 | |
54 | void BackgroundIndexRebuilder::startLoading() { |
55 | std::lock_guard<std::mutex> Lock(Mu); |
56 | if (!Loading) |
57 | LoadedShards = 0; |
58 | ++Loading; |
59 | } |
60 | void BackgroundIndexRebuilder::loadedShard(size_t ShardCount) { |
61 | std::lock_guard<std::mutex> Lock(Mu); |
62 | assert(Loading); |
63 | LoadedShards += ShardCount; |
64 | } |
65 | void 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 | |
76 | void BackgroundIndexRebuilder::shutdown() { |
77 | std::lock_guard<std::mutex> Lock(Mu); |
78 | ShouldStop = true; |
79 | } |
80 | |
81 | void 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 | |