Skip to content

Commit 9c37710

Browse files
author
Azharuddin Mohammed
committed
Revert r366458, r366467 and r366468
r366458 is causing test failures. r366467 and r366468 had to be reverted as they were casuing conflict while reverting r366458. r366468 [clangd] Remove dead code from BackgroundIndex r366467 [clangd] BackgroundIndex stores shards to the closest project r366458 [clangd] Refactor background-index shard loading llvm-svn: 366551
1 parent e9e59ad commit 9c37710

15 files changed

+225
-367
lines changed

clang-tools-extra/clangd/CMakeLists.txt

-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,6 @@ add_clang_library(clangDaemon
7373
XRefs.cpp
7474

7575
index/Background.cpp
76-
index/BackgroundIndexLoader.cpp
7776
index/BackgroundIndexStorage.cpp
7877
index/BackgroundQueue.cpp
7978
index/BackgroundRebuild.cpp

clang-tools-extra/clangd/ClangdServer.cpp

+1-2
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,7 @@ ClangdServer::ClangdServer(const GlobalCompilationDatabase &CDB,
127127
if (Opts.BackgroundIndex) {
128128
BackgroundIdx = llvm::make_unique<BackgroundIndex>(
129129
Context::current().clone(), FSProvider, CDB,
130-
BackgroundIndexStorage::createDiskBackedStorageFactory(
131-
[&CDB](llvm::StringRef File) { return CDB.getProjectInfo(File); }));
130+
BackgroundIndexStorage::createDiskBackedStorageFactory());
132131
AddIndex(BackgroundIdx.get());
133132
}
134133
if (DynamicIdx)

clang-tools-extra/clangd/index/Background.cpp

+175-93
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
#include "ClangdUnit.h"
1111
#include "Compiler.h"
1212
#include "Context.h"
13-
#include "FSProvider.h"
1413
#include "Headers.h"
1514
#include "Logger.h"
1615
#include "Path.h"
@@ -19,7 +18,6 @@
1918
#include "Threading.h"
2019
#include "Trace.h"
2120
#include "URI.h"
22-
#include "index/BackgroundIndexLoader.h"
2321
#include "index/FileIndex.h"
2422
#include "index/IndexAction.h"
2523
#include "index/MemIndex.h"
@@ -30,8 +28,6 @@
3028
#include "clang/Basic/SourceLocation.h"
3129
#include "clang/Basic/SourceManager.h"
3230
#include "clang/Driver/Types.h"
33-
#include "llvm/ADT/ArrayRef.h"
34-
#include "llvm/ADT/DenseSet.h"
3531
#include "llvm/ADT/Hashing.h"
3632
#include "llvm/ADT/STLExtras.h"
3733
#include "llvm/ADT/ScopeExit.h"
@@ -46,16 +42,13 @@
4642
#include <atomic>
4743
#include <chrono>
4844
#include <condition_variable>
49-
#include <cstddef>
5045
#include <memory>
5146
#include <mutex>
5247
#include <numeric>
5348
#include <queue>
5449
#include <random>
5550
#include <string>
5651
#include <thread>
57-
#include <utility>
58-
#include <vector>
5952

6053
namespace clang {
6154
namespace clangd {
@@ -126,18 +119,6 @@ llvm::SmallString<128> getAbsolutePath(const tooling::CompileCommand &Cmd) {
126119
}
127120
return AbsolutePath;
128121
}
129-
130-
bool shardIsStale(const LoadedShard &LS, llvm::vfs::FileSystem *FS) {
131-
auto Buf = FS->getBufferForFile(LS.AbsolutePath);
132-
if (!Buf) {
133-
elog("Background-index: Couldn't read {0} to validate stored index: {1}",
134-
LS.AbsolutePath, Buf.getError().message());
135-
// There is no point in indexing an unreadable file.
136-
return false;
137-
}
138-
return digest(Buf->get()->getBuffer()) != LS.Digest;
139-
}
140-
141122
} // namespace
142123

143124
BackgroundIndex::BackgroundIndex(
@@ -175,14 +156,14 @@ BackgroundQueue::Task BackgroundIndex::changedFilesTask(
175156
log("Enqueueing {0} commands for indexing", ChangedFiles.size());
176157
SPAN_ATTACH(Tracer, "files", int64_t(ChangedFiles.size()));
177158

178-
auto NeedsReIndexing = loadProject(std::move(ChangedFiles));
159+
auto NeedsReIndexing = loadShards(std::move(ChangedFiles));
179160
// Run indexing for files that need to be updated.
180161
std::shuffle(NeedsReIndexing.begin(), NeedsReIndexing.end(),
181162
std::mt19937(std::random_device{}()));
182163
std::vector<BackgroundQueue::Task> Tasks;
183164
Tasks.reserve(NeedsReIndexing.size());
184-
for (auto &Cmd : NeedsReIndexing)
185-
Tasks.push_back(indexFileTask(std::move(Cmd)));
165+
for (auto &Elem : NeedsReIndexing)
166+
Tasks.push_back(indexFileTask(std::move(Elem.first), Elem.second));
186167
Queue.append(std::move(Tasks));
187168
});
188169

@@ -197,12 +178,13 @@ static llvm::StringRef filenameWithoutExtension(llvm::StringRef Path) {
197178
}
198179

199180
BackgroundQueue::Task
200-
BackgroundIndex::indexFileTask(tooling::CompileCommand Cmd) {
201-
BackgroundQueue::Task T([this, Cmd] {
181+
BackgroundIndex::indexFileTask(tooling::CompileCommand Cmd,
182+
BackgroundIndexStorage *Storage) {
183+
BackgroundQueue::Task T([this, Storage, Cmd] {
202184
// We can't use llvm::StringRef here since we are going to
203185
// move from Cmd during the call below.
204186
const std::string FileName = Cmd.Filename;
205-
if (auto Error = index(std::move(Cmd)))
187+
if (auto Error = index(std::move(Cmd), Storage))
206188
elog("Indexing {0} failed: {1}", FileName, std::move(Error));
207189
});
208190
T.QueuePri = IndexFile;
@@ -225,7 +207,7 @@ void BackgroundIndex::boostRelated(llvm::StringRef Path) {
225207
void BackgroundIndex::update(
226208
llvm::StringRef MainFile, IndexFileIn Index,
227209
const llvm::StringMap<ShardVersion> &ShardVersionsSnapshot,
228-
bool HadErrors) {
210+
BackgroundIndexStorage *IndexStorage, bool HadErrors) {
229211
// Partition symbols/references into files.
230212
struct File {
231213
llvm::DenseSet<const Symbol *> Symbols;
@@ -309,21 +291,22 @@ void BackgroundIndex::update(
309291
// We need to store shards before updating the index, since the latter
310292
// consumes slabs.
311293
// FIXME: Also skip serializing the shard if it is already up-to-date.
312-
BackgroundIndexStorage *IndexStorage = IndexStorageFactory(Path);
313-
IndexFileOut Shard;
314-
Shard.Symbols = SS.get();
315-
Shard.Refs = RS.get();
316-
Shard.Relations = RelS.get();
317-
Shard.Sources = IG.get();
318-
319-
// Only store command line hash for main files of the TU, since our
320-
// current model keeps only one version of a header file.
321-
if (Path == MainFile)
322-
Shard.Cmd = Index.Cmd.getPointer();
323-
324-
if (auto Error = IndexStorage->storeShard(Path, Shard))
325-
elog("Failed to write background-index shard for file {0}: {1}", Path,
326-
std::move(Error));
294+
if (IndexStorage) {
295+
IndexFileOut Shard;
296+
Shard.Symbols = SS.get();
297+
Shard.Refs = RS.get();
298+
Shard.Relations = RelS.get();
299+
Shard.Sources = IG.get();
300+
301+
// Only store command line hash for main files of the TU, since our
302+
// current model keeps only one version of a header file.
303+
if (Path == MainFile)
304+
Shard.Cmd = Index.Cmd.getPointer();
305+
306+
if (auto Error = IndexStorage->storeShard(Path, Shard))
307+
elog("Failed to write background-index shard for file {0}: {1}", Path,
308+
std::move(Error));
309+
}
327310

328311
{
329312
std::lock_guard<std::mutex> Lock(ShardVersionsMu);
@@ -346,7 +329,8 @@ void BackgroundIndex::update(
346329
}
347330
}
348331

349-
llvm::Error BackgroundIndex::index(tooling::CompileCommand Cmd) {
332+
llvm::Error BackgroundIndex::index(tooling::CompileCommand Cmd,
333+
BackgroundIndexStorage *IndexStorage) {
350334
trace::Span Tracer("BackgroundIndex");
351335
SPAN_ATTACH(Tracer, "file", Cmd.Filename);
352336
auto AbsolutePath = getAbsolutePath(Cmd);
@@ -440,78 +424,176 @@ llvm::Error BackgroundIndex::index(tooling::CompileCommand Cmd) {
440424
for (auto &It : *Index.Sources)
441425
It.second.Flags |= IncludeGraphNode::SourceFlag::HadErrors;
442426
}
443-
update(AbsolutePath, std::move(Index), ShardVersionsSnapshot, HadErrors);
427+
update(AbsolutePath, std::move(Index), ShardVersionsSnapshot, IndexStorage,
428+
HadErrors);
444429

445430
Rebuilder.indexedTU();
446431
return llvm::Error::success();
447432
}
448433

449-
// Restores shards for \p MainFiles from index storage. Then checks staleness of
450-
// those shards and returns a list of TUs that needs to be indexed to update
451-
// staleness.
452-
std::vector<tooling::CompileCommand>
453-
BackgroundIndex::loadProject(std::vector<std::string> MainFiles) {
454-
std::vector<tooling::CompileCommand> NeedsReIndexing;
434+
std::vector<BackgroundIndex::Source>
435+
BackgroundIndex::loadShard(const tooling::CompileCommand &Cmd,
436+
BackgroundIndexStorage *IndexStorage,
437+
llvm::StringSet<> &LoadedShards) {
438+
struct ShardInfo {
439+
std::string AbsolutePath;
440+
std::unique_ptr<IndexFileIn> Shard;
441+
FileDigest Digest = {};
442+
bool CountReferences = false;
443+
bool HadErrors = false;
444+
};
445+
std::vector<ShardInfo> IntermediateSymbols;
446+
// Make sure we don't have duplicate elements in the queue. Keys are absolute
447+
// paths.
448+
llvm::StringSet<> InQueue;
449+
auto FS = FSProvider.getFileSystem();
450+
// Dependencies of this TU, paired with the information about whether they
451+
// need to be re-indexed or not.
452+
std::vector<Source> Dependencies;
453+
std::queue<Source> ToVisit;
454+
std::string AbsolutePath = getAbsolutePath(Cmd).str();
455+
// Up until we load the shard related to a dependency it needs to be
456+
// re-indexed.
457+
ToVisit.emplace(AbsolutePath, true);
458+
InQueue.insert(AbsolutePath);
459+
// Goes over each dependency.
460+
while (!ToVisit.empty()) {
461+
Dependencies.push_back(std::move(ToVisit.front()));
462+
// Dependencies is not modified during the rest of the loop, so it is safe
463+
// to keep the reference.
464+
auto &CurDependency = Dependencies.back();
465+
ToVisit.pop();
466+
// If we have already seen this shard before(either loaded or failed) don't
467+
// re-try again. Since the information in the shard won't change from one TU
468+
// to another.
469+
if (!LoadedShards.try_emplace(CurDependency.Path).second) {
470+
// If the dependency needs to be re-indexed, first occurence would already
471+
// have detected that, so we don't need to issue it again.
472+
CurDependency.NeedsReIndexing = false;
473+
continue;
474+
}
455475

456-
Rebuilder.startLoading();
457-
// Load shards for all of the mainfiles.
458-
const std::vector<LoadedShard> Result =
459-
loadIndexShards(MainFiles, IndexStorageFactory, CDB);
460-
size_t LoadedShards = 0;
476+
auto Shard = IndexStorage->loadShard(CurDependency.Path);
477+
if (!Shard || !Shard->Sources) {
478+
// File will be returned as requiring re-indexing to caller.
479+
vlog("Failed to load shard: {0}", CurDependency.Path);
480+
continue;
481+
}
482+
// These are the edges in the include graph for current dependency.
483+
for (const auto &I : *Shard->Sources) {
484+
auto U = URI::parse(I.getKey());
485+
if (!U)
486+
continue;
487+
auto AbsolutePath = URI::resolve(*U, CurDependency.Path);
488+
if (!AbsolutePath)
489+
continue;
490+
// Add file as dependency if haven't seen before.
491+
if (InQueue.try_emplace(*AbsolutePath).second)
492+
ToVisit.emplace(*AbsolutePath, true);
493+
// The node contains symbol information only for current file, the rest is
494+
// just edges.
495+
if (*AbsolutePath != CurDependency.Path)
496+
continue;
497+
498+
// We found source file info for current dependency.
499+
assert(I.getValue().Digest != FileDigest{{0}} && "Digest is empty?");
500+
ShardInfo SI;
501+
SI.AbsolutePath = CurDependency.Path;
502+
SI.Shard = std::move(Shard);
503+
SI.Digest = I.getValue().Digest;
504+
SI.CountReferences =
505+
I.getValue().Flags & IncludeGraphNode::SourceFlag::IsTU;
506+
SI.HadErrors =
507+
I.getValue().Flags & IncludeGraphNode::SourceFlag::HadErrors;
508+
IntermediateSymbols.push_back(std::move(SI));
509+
// Check if the source needs re-indexing.
510+
// Get the digest, skip it if file doesn't exist.
511+
auto Buf = FS->getBufferForFile(CurDependency.Path);
512+
if (!Buf) {
513+
elog("Couldn't get buffer for file: {0}: {1}", CurDependency.Path,
514+
Buf.getError().message());
515+
continue;
516+
}
517+
// If digests match then dependency doesn't need re-indexing.
518+
// FIXME: Also check for dependencies(sources) of this shard and compile
519+
// commands for cache invalidation.
520+
CurDependency.NeedsReIndexing =
521+
digest(Buf->get()->getBuffer()) != I.getValue().Digest;
522+
}
523+
}
524+
// Load shard information into background-index.
461525
{
462-
// Update in-memory state.
463526
std::lock_guard<std::mutex> Lock(ShardVersionsMu);
464-
for (auto &LS : Result) {
465-
if (!LS.Shard)
466-
continue;
527+
// This can override a newer version that is added in another thread,
528+
// if this thread sees the older version but finishes later. This
529+
// should be rare in practice.
530+
for (const ShardInfo &SI : IntermediateSymbols) {
467531
auto SS =
468-
LS.Shard->Symbols
469-
? llvm::make_unique<SymbolSlab>(std::move(*LS.Shard->Symbols))
532+
SI.Shard->Symbols
533+
? llvm::make_unique<SymbolSlab>(std::move(*SI.Shard->Symbols))
470534
: nullptr;
471-
auto RS = LS.Shard->Refs
472-
? llvm::make_unique<RefSlab>(std::move(*LS.Shard->Refs))
535+
auto RS = SI.Shard->Refs
536+
? llvm::make_unique<RefSlab>(std::move(*SI.Shard->Refs))
473537
: nullptr;
474538
auto RelS =
475-
LS.Shard->Relations
476-
? llvm::make_unique<RelationSlab>(std::move(*LS.Shard->Relations))
539+
SI.Shard->Relations
540+
? llvm::make_unique<RelationSlab>(std::move(*SI.Shard->Relations))
477541
: nullptr;
478-
ShardVersion &SV = ShardVersions[LS.AbsolutePath];
479-
SV.Digest = LS.Digest;
480-
SV.HadErrors = LS.HadErrors;
481-
++LoadedShards;
542+
ShardVersion &SV = ShardVersions[SI.AbsolutePath];
543+
SV.Digest = SI.Digest;
544+
SV.HadErrors = SI.HadErrors;
482545

483-
IndexedSymbols.update(LS.AbsolutePath, std::move(SS), std::move(RS),
484-
std::move(RelS), LS.CountReferences);
546+
IndexedSymbols.update(SI.AbsolutePath, std::move(SS), std::move(RS),
547+
std::move(RelS), SI.CountReferences);
485548
}
486549
}
487-
Rebuilder.loadedShard(LoadedShards);
488-
Rebuilder.doneLoading();
550+
if (!IntermediateSymbols.empty())
551+
Rebuilder.loadedTU();
489552

490-
auto FS = FSProvider.getFileSystem();
491-
llvm::DenseSet<PathRef> TUsToIndex;
492-
// We'll accept data from stale shards, but ensure the files get reindexed
493-
// soon.
494-
for (auto &LS : Result) {
495-
if (!shardIsStale(LS, FS.get()))
496-
continue;
497-
PathRef TUForFile = LS.DependentTU;
498-
assert(!TUForFile.empty() && "File without a TU!");
499-
500-
// FIXME: Currently, we simply schedule indexing on a TU whenever any of
501-
// its dependencies needs re-indexing. We might do it smarter by figuring
502-
// out a minimal set of TUs that will cover all the stale dependencies.
503-
// FIXME: Try looking at other TUs if no compile commands are available
504-
// for this TU, i.e TU was deleted after we performed indexing.
505-
TUsToIndex.insert(TUForFile);
506-
}
553+
return Dependencies;
554+
}
507555

508-
for (PathRef TU : TUsToIndex) {
509-
auto Cmd = CDB.getCompileCommand(TU);
556+
// Goes over each changed file and loads them from index. Returns the list of
557+
// TUs that had out-of-date/no shards.
558+
std::vector<std::pair<tooling::CompileCommand, BackgroundIndexStorage *>>
559+
BackgroundIndex::loadShards(std::vector<std::string> ChangedFiles) {
560+
std::vector<std::pair<tooling::CompileCommand, BackgroundIndexStorage *>>
561+
NeedsReIndexing;
562+
// Keeps track of the files that will be reindexed, to make sure we won't
563+
// re-index same dependencies more than once. Keys are AbsolutePaths.
564+
llvm::StringSet<> FilesToIndex;
565+
// Keeps track of the loaded shards to make sure we don't perform redundant
566+
// disk IO. Keys are absolute paths.
567+
llvm::StringSet<> LoadedShards;
568+
Rebuilder.startLoading();
569+
for (const auto &File : ChangedFiles) {
570+
auto Cmd = CDB.getCompileCommand(File);
510571
if (!Cmd)
511572
continue;
512-
NeedsReIndexing.emplace_back(std::move(*Cmd));
513-
}
514573

574+
std::string ProjectRoot;
575+
if (auto PI = CDB.getProjectInfo(File))
576+
ProjectRoot = std::move(PI->SourceRoot);
577+
578+
BackgroundIndexStorage *IndexStorage = IndexStorageFactory(ProjectRoot);
579+
auto Dependencies = loadShard(*Cmd, IndexStorage, LoadedShards);
580+
for (const auto &Dependency : Dependencies) {
581+
if (!Dependency.NeedsReIndexing || FilesToIndex.count(Dependency.Path))
582+
continue;
583+
// FIXME: Currently, we simply schedule indexing on a TU whenever any of
584+
// its dependencies needs re-indexing. We might do it smarter by figuring
585+
// out a minimal set of TUs that will cover all the stale dependencies.
586+
vlog("Enqueueing TU {0} because its dependency {1} needs re-indexing.",
587+
Cmd->Filename, Dependency.Path);
588+
NeedsReIndexing.push_back({std::move(*Cmd), IndexStorage});
589+
// Mark all of this TU's dependencies as to-be-indexed so that we won't
590+
// try to re-index those.
591+
for (const auto &Dependency : Dependencies)
592+
FilesToIndex.insert(Dependency.Path);
593+
break;
594+
}
595+
}
596+
Rebuilder.doneLoading();
515597
return NeedsReIndexing;
516598
}
517599

0 commit comments

Comments
 (0)