[clangd] Minimal implementation of automatic static index (not enabled).
Summary:
See tinyurl.com/clangd-automatic-index for design and goals.
Lots of limitations to keep this patch smallish, TODOs everywhere:
- no serialization to disk
- no changes to dynamic index, which now has a much simpler job
- no partitioning of symbols by file to avoid duplication of header symbols
- no reindexing of edited files
- only a single worker thread
- compilation database is slurped synchronously (doesn't scale)
- uses memindex, rebuilds after every file (should be dex, periodically)
It's not hooked up to ClangdServer/ClangdLSPServer yet: the layering
isn't clear (it should really be in ClangdServer, but ClangdLSPServer
has all the CDB interactions).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, jfb, cfe-commits
Differential Revision: https://reviews.llvm.org/D53032
llvm-svn: 344513
2018-10-15 21:34:10 +08:00
|
|
|
//===-- Background.cpp - Build an index in a background thread ------------===//
|
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// 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
|
[clangd] Minimal implementation of automatic static index (not enabled).
Summary:
See tinyurl.com/clangd-automatic-index for design and goals.
Lots of limitations to keep this patch smallish, TODOs everywhere:
- no serialization to disk
- no changes to dynamic index, which now has a much simpler job
- no partitioning of symbols by file to avoid duplication of header symbols
- no reindexing of edited files
- only a single worker thread
- compilation database is slurped synchronously (doesn't scale)
- uses memindex, rebuilds after every file (should be dex, periodically)
It's not hooked up to ClangdServer/ClangdLSPServer yet: the layering
isn't clear (it should really be in ClangdServer, but ClangdLSPServer
has all the CDB interactions).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, jfb, cfe-commits
Differential Revision: https://reviews.llvm.org/D53032
llvm-svn: 344513
2018-10-15 21:34:10 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "index/Background.h"
|
|
|
|
#include "ClangdUnit.h"
|
|
|
|
#include "Compiler.h"
|
|
|
|
#include "Logger.h"
|
2018-11-28 00:08:53 +08:00
|
|
|
#include "SourceCode.h"
|
2018-10-30 20:13:27 +08:00
|
|
|
#include "Threading.h"
|
[clangd] Minimal implementation of automatic static index (not enabled).
Summary:
See tinyurl.com/clangd-automatic-index for design and goals.
Lots of limitations to keep this patch smallish, TODOs everywhere:
- no serialization to disk
- no changes to dynamic index, which now has a much simpler job
- no partitioning of symbols by file to avoid duplication of header symbols
- no reindexing of edited files
- only a single worker thread
- compilation database is slurped synchronously (doesn't scale)
- uses memindex, rebuilds after every file (should be dex, periodically)
It's not hooked up to ClangdServer/ClangdLSPServer yet: the layering
isn't clear (it should really be in ClangdServer, but ClangdLSPServer
has all the CDB interactions).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, jfb, cfe-commits
Differential Revision: https://reviews.llvm.org/D53032
llvm-svn: 344513
2018-10-15 21:34:10 +08:00
|
|
|
#include "Trace.h"
|
2018-11-06 18:55:21 +08:00
|
|
|
#include "URI.h"
|
[clangd] Minimal implementation of automatic static index (not enabled).
Summary:
See tinyurl.com/clangd-automatic-index for design and goals.
Lots of limitations to keep this patch smallish, TODOs everywhere:
- no serialization to disk
- no changes to dynamic index, which now has a much simpler job
- no partitioning of symbols by file to avoid duplication of header symbols
- no reindexing of edited files
- only a single worker thread
- compilation database is slurped synchronously (doesn't scale)
- uses memindex, rebuilds after every file (should be dex, periodically)
It's not hooked up to ClangdServer/ClangdLSPServer yet: the layering
isn't clear (it should really be in ClangdServer, but ClangdLSPServer
has all the CDB interactions).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, jfb, cfe-commits
Differential Revision: https://reviews.llvm.org/D53032
llvm-svn: 344513
2018-10-15 21:34:10 +08:00
|
|
|
#include "index/IndexAction.h"
|
|
|
|
#include "index/MemIndex.h"
|
|
|
|
#include "index/Serialization.h"
|
2018-11-06 18:55:21 +08:00
|
|
|
#include "index/SymbolCollector.h"
|
|
|
|
#include "clang/Basic/SourceLocation.h"
|
|
|
|
#include "clang/Basic/SourceManager.h"
|
|
|
|
#include "llvm/ADT/STLExtras.h"
|
2018-12-17 20:30:27 +08:00
|
|
|
#include "llvm/ADT/ScopeExit.h"
|
2018-11-06 18:55:21 +08:00
|
|
|
#include "llvm/ADT/StringMap.h"
|
|
|
|
#include "llvm/ADT/StringRef.h"
|
[clangd] Minimal implementation of automatic static index (not enabled).
Summary:
See tinyurl.com/clangd-automatic-index for design and goals.
Lots of limitations to keep this patch smallish, TODOs everywhere:
- no serialization to disk
- no changes to dynamic index, which now has a much simpler job
- no partitioning of symbols by file to avoid duplication of header symbols
- no reindexing of edited files
- only a single worker thread
- compilation database is slurped synchronously (doesn't scale)
- uses memindex, rebuilds after every file (should be dex, periodically)
It's not hooked up to ClangdServer/ClangdLSPServer yet: the layering
isn't clear (it should really be in ClangdServer, but ClangdLSPServer
has all the CDB interactions).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, jfb, cfe-commits
Differential Revision: https://reviews.llvm.org/D53032
llvm-svn: 344513
2018-10-15 21:34:10 +08:00
|
|
|
#include "llvm/Support/SHA1.h"
|
2018-11-16 17:03:56 +08:00
|
|
|
|
2018-12-18 23:39:33 +08:00
|
|
|
#include <chrono>
|
2018-11-16 17:03:56 +08:00
|
|
|
#include <memory>
|
2018-11-26 21:35:02 +08:00
|
|
|
#include <numeric>
|
2018-11-16 17:03:56 +08:00
|
|
|
#include <queue>
|
[clangd] Minimal implementation of automatic static index (not enabled).
Summary:
See tinyurl.com/clangd-automatic-index for design and goals.
Lots of limitations to keep this patch smallish, TODOs everywhere:
- no serialization to disk
- no changes to dynamic index, which now has a much simpler job
- no partitioning of symbols by file to avoid duplication of header symbols
- no reindexing of edited files
- only a single worker thread
- compilation database is slurped synchronously (doesn't scale)
- uses memindex, rebuilds after every file (should be dex, periodically)
It's not hooked up to ClangdServer/ClangdLSPServer yet: the layering
isn't clear (it should really be in ClangdServer, but ClangdLSPServer
has all the CDB interactions).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, jfb, cfe-commits
Differential Revision: https://reviews.llvm.org/D53032
llvm-svn: 344513
2018-10-15 21:34:10 +08:00
|
|
|
#include <random>
|
2018-11-06 18:55:21 +08:00
|
|
|
#include <string>
|
2018-12-18 23:39:33 +08:00
|
|
|
#include <thread>
|
[clangd] Minimal implementation of automatic static index (not enabled).
Summary:
See tinyurl.com/clangd-automatic-index for design and goals.
Lots of limitations to keep this patch smallish, TODOs everywhere:
- no serialization to disk
- no changes to dynamic index, which now has a much simpler job
- no partitioning of symbols by file to avoid duplication of header symbols
- no reindexing of edited files
- only a single worker thread
- compilation database is slurped synchronously (doesn't scale)
- uses memindex, rebuilds after every file (should be dex, periodically)
It's not hooked up to ClangdServer/ClangdLSPServer yet: the layering
isn't clear (it should really be in ClangdServer, but ClangdLSPServer
has all the CDB interactions).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, jfb, cfe-commits
Differential Revision: https://reviews.llvm.org/D53032
llvm-svn: 344513
2018-10-15 21:34:10 +08:00
|
|
|
|
|
|
|
namespace clang {
|
|
|
|
namespace clangd {
|
2018-12-04 19:31:57 +08:00
|
|
|
namespace {
|
|
|
|
// Resolves URI to file paths with cache.
|
|
|
|
class URIToFileCache {
|
|
|
|
public:
|
|
|
|
URIToFileCache(llvm::StringRef HintPath) : HintPath(HintPath) {}
|
|
|
|
|
|
|
|
llvm::StringRef resolve(llvm::StringRef FileURI) {
|
|
|
|
auto I = URIToPathCache.try_emplace(FileURI);
|
|
|
|
if (I.second) {
|
|
|
|
auto U = URI::parse(FileURI);
|
|
|
|
if (!U) {
|
|
|
|
elog("Failed to parse URI {0}: {1}", FileURI, U.takeError());
|
|
|
|
assert(false && "Failed to parse URI");
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
auto Path = URI::resolve(*U, HintPath);
|
|
|
|
if (!Path) {
|
|
|
|
elog("Failed to resolve URI {0}: {1}", FileURI, Path.takeError());
|
|
|
|
assert(false && "Failed to resolve URI");
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
I.first->second = *Path;
|
|
|
|
}
|
|
|
|
return I.first->second;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
std::string HintPath;
|
|
|
|
llvm::StringMap<std::string> URIToPathCache;
|
|
|
|
};
|
|
|
|
|
|
|
|
// We keep only the node "U" and its edges. Any node other than "U" will be
|
|
|
|
// empty in the resultant graph.
|
|
|
|
IncludeGraph getSubGraph(const URI &U, const IncludeGraph &FullGraph) {
|
|
|
|
IncludeGraph IG;
|
|
|
|
|
|
|
|
std::string FileURI = U.toString();
|
|
|
|
auto Entry = IG.try_emplace(FileURI).first;
|
|
|
|
auto &Node = Entry->getValue();
|
|
|
|
Node = FullGraph.lookup(Entry->getKey());
|
|
|
|
Node.URI = Entry->getKey();
|
|
|
|
|
|
|
|
// URIs inside nodes must point into the keys of the same IncludeGraph.
|
|
|
|
for (auto &Include : Node.DirectIncludes) {
|
|
|
|
auto I = IG.try_emplace(Include).first;
|
|
|
|
I->getValue().URI = I->getKey();
|
|
|
|
Include = I->getKey();
|
|
|
|
}
|
|
|
|
|
|
|
|
return IG;
|
|
|
|
}
|
2018-12-13 21:07:29 +08:00
|
|
|
|
|
|
|
// Creates a filter to not collect index results from files with unchanged
|
|
|
|
// digests.
|
2019-01-15 17:03:33 +08:00
|
|
|
// \p FileDigests contains file digests for the current indexed files.
|
2018-12-13 21:07:29 +08:00
|
|
|
decltype(SymbolCollector::Options::FileFilter)
|
2019-01-15 17:03:33 +08:00
|
|
|
createFileFilter(const llvm::StringMap<FileDigest> &FileDigests) {
|
|
|
|
return [&FileDigests](const SourceManager &SM, FileID FID) {
|
2018-12-19 18:46:21 +08:00
|
|
|
const auto *F = SM.getFileEntryForID(FID);
|
|
|
|
if (!F)
|
2018-12-13 21:07:29 +08:00
|
|
|
return false; // Skip invalid files.
|
2018-12-19 18:46:21 +08:00
|
|
|
auto AbsPath = getCanonicalPath(F, SM);
|
|
|
|
if (!AbsPath)
|
2018-12-13 21:07:29 +08:00
|
|
|
return false; // Skip files without absolute path.
|
|
|
|
auto Digest = digestFile(SM, FID);
|
|
|
|
if (!Digest)
|
|
|
|
return false;
|
2018-12-19 18:46:21 +08:00
|
|
|
auto D = FileDigests.find(*AbsPath);
|
2018-12-13 21:07:29 +08:00
|
|
|
if (D != FileDigests.end() && D->second == Digest)
|
|
|
|
return false; // Skip files that haven't changed.
|
|
|
|
return true;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2019-01-11 01:03:04 +08:00
|
|
|
// We cannot use vfs->makeAbsolute because Cmd.FileName is either absolute or
|
|
|
|
// relative to Cmd.Directory, which might not be the same as current working
|
|
|
|
// directory.
|
|
|
|
llvm::SmallString<128> getAbsolutePath(const tooling::CompileCommand &Cmd) {
|
|
|
|
llvm::SmallString<128> AbsolutePath;
|
|
|
|
if (llvm::sys::path::is_absolute(Cmd.Filename)) {
|
|
|
|
AbsolutePath = Cmd.Filename;
|
|
|
|
} else {
|
|
|
|
AbsolutePath = Cmd.Directory;
|
|
|
|
llvm::sys::path::append(AbsolutePath, Cmd.Filename);
|
|
|
|
}
|
|
|
|
return AbsolutePath;
|
|
|
|
}
|
2018-12-04 19:31:57 +08:00
|
|
|
} // namespace
|
[clangd] Minimal implementation of automatic static index (not enabled).
Summary:
See tinyurl.com/clangd-automatic-index for design and goals.
Lots of limitations to keep this patch smallish, TODOs everywhere:
- no serialization to disk
- no changes to dynamic index, which now has a much simpler job
- no partitioning of symbols by file to avoid duplication of header symbols
- no reindexing of edited files
- only a single worker thread
- compilation database is slurped synchronously (doesn't scale)
- uses memindex, rebuilds after every file (should be dex, periodically)
It's not hooked up to ClangdServer/ClangdLSPServer yet: the layering
isn't clear (it should really be in ClangdServer, but ClangdLSPServer
has all the CDB interactions).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, jfb, cfe-commits
Differential Revision: https://reviews.llvm.org/D53032
llvm-svn: 344513
2018-10-15 21:34:10 +08:00
|
|
|
|
2018-11-16 17:03:56 +08:00
|
|
|
BackgroundIndex::BackgroundIndex(
|
2019-01-07 23:45:19 +08:00
|
|
|
Context BackgroundContext, llvm::StringRef ResourceDir,
|
[clangd] Auto-index watches global CDB for changes.
Summary:
Instead of receiving compilation commands, auto-index is triggered by just
filenames to reindex, and gets commands from the global comp DB internally.
This has advantages:
- more of the work can be done asynchronously (fetching compilation commands
upfront can be slow for large CDBs)
- we get access to the CDB which can be used to retrieve interpolated commands
for headers (useful in some cases where the original TU goes away)
- fits nicely with the filename-only change observation from r347297
The interface to GlobalCompilationDatabase gets extended: when retrieving a
compile command, the GCDB can optionally report the project the file belongs to.
This naturally fits together with getCompileCommand: it's hard to implement one
without the other. But because most callers don't care, I've ended up with an
awkward optional-out-param-in-virtual method pattern - maybe there's a better
one.
This is the main missing integration point between ClangdServer and
BackgroundIndex, after this we should be able to add an auto-index flag.
Reviewers: ioeric, kadircet
Subscribers: MaskRay, jkorous, arphaman, cfe-commits, ilya-biryukov
Differential Revision: https://reviews.llvm.org/D54865
llvm-svn: 347538
2018-11-26 17:51:50 +08:00
|
|
|
const FileSystemProvider &FSProvider, const GlobalCompilationDatabase &CDB,
|
2018-12-18 23:39:33 +08:00
|
|
|
BackgroundIndexStorage::Factory IndexStorageFactory,
|
|
|
|
size_t BuildIndexPeriodMs, size_t ThreadPoolSize)
|
2019-01-07 23:45:19 +08:00
|
|
|
: SwapIndex(llvm::make_unique<MemIndex>()), ResourceDir(ResourceDir),
|
[clangd] Auto-index watches global CDB for changes.
Summary:
Instead of receiving compilation commands, auto-index is triggered by just
filenames to reindex, and gets commands from the global comp DB internally.
This has advantages:
- more of the work can be done asynchronously (fetching compilation commands
upfront can be slow for large CDBs)
- we get access to the CDB which can be used to retrieve interpolated commands
for headers (useful in some cases where the original TU goes away)
- fits nicely with the filename-only change observation from r347297
The interface to GlobalCompilationDatabase gets extended: when retrieving a
compile command, the GCDB can optionally report the project the file belongs to.
This naturally fits together with getCompileCommand: it's hard to implement one
without the other. But because most callers don't care, I've ended up with an
awkward optional-out-param-in-virtual method pattern - maybe there's a better
one.
This is the main missing integration point between ClangdServer and
BackgroundIndex, after this we should be able to add an auto-index flag.
Reviewers: ioeric, kadircet
Subscribers: MaskRay, jkorous, arphaman, cfe-commits, ilya-biryukov
Differential Revision: https://reviews.llvm.org/D54865
llvm-svn: 347538
2018-11-26 17:51:50 +08:00
|
|
|
FSProvider(FSProvider), CDB(CDB),
|
|
|
|
BackgroundContext(std::move(BackgroundContext)),
|
2018-12-18 23:39:33 +08:00
|
|
|
BuildIndexPeriodMs(BuildIndexPeriodMs),
|
|
|
|
SymbolsUpdatedSinceLastIndex(false),
|
[clangd] Auto-index watches global CDB for changes.
Summary:
Instead of receiving compilation commands, auto-index is triggered by just
filenames to reindex, and gets commands from the global comp DB internally.
This has advantages:
- more of the work can be done asynchronously (fetching compilation commands
upfront can be slow for large CDBs)
- we get access to the CDB which can be used to retrieve interpolated commands
for headers (useful in some cases where the original TU goes away)
- fits nicely with the filename-only change observation from r347297
The interface to GlobalCompilationDatabase gets extended: when retrieving a
compile command, the GCDB can optionally report the project the file belongs to.
This naturally fits together with getCompileCommand: it's hard to implement one
without the other. But because most callers don't care, I've ended up with an
awkward optional-out-param-in-virtual method pattern - maybe there's a better
one.
This is the main missing integration point between ClangdServer and
BackgroundIndex, after this we should be able to add an auto-index flag.
Reviewers: ioeric, kadircet
Subscribers: MaskRay, jkorous, arphaman, cfe-commits, ilya-biryukov
Differential Revision: https://reviews.llvm.org/D54865
llvm-svn: 347538
2018-11-26 17:51:50 +08:00
|
|
|
IndexStorageFactory(std::move(IndexStorageFactory)),
|
|
|
|
CommandsChanged(
|
|
|
|
CDB.watch([&](const std::vector<std::string> &ChangedFiles) {
|
|
|
|
enqueue(ChangedFiles);
|
|
|
|
})) {
|
2018-10-30 20:13:27 +08:00
|
|
|
assert(ThreadPoolSize > 0 && "Thread pool size can't be zero.");
|
2018-11-16 17:41:14 +08:00
|
|
|
assert(this->IndexStorageFactory && "Storage factory can not be null!");
|
2018-12-17 20:30:27 +08:00
|
|
|
while (ThreadPoolSize--)
|
2018-10-30 20:13:27 +08:00
|
|
|
ThreadPool.emplace_back([this] { run(); });
|
2018-12-18 23:39:33 +08:00
|
|
|
if (BuildIndexPeriodMs > 0) {
|
|
|
|
log("BackgroundIndex: build symbol index periodically every {0} ms.",
|
|
|
|
BuildIndexPeriodMs);
|
|
|
|
ThreadPool.emplace_back([this] { buildIndex(); });
|
|
|
|
}
|
2018-10-30 20:13:27 +08:00
|
|
|
}
|
[clangd] Minimal implementation of automatic static index (not enabled).
Summary:
See tinyurl.com/clangd-automatic-index for design and goals.
Lots of limitations to keep this patch smallish, TODOs everywhere:
- no serialization to disk
- no changes to dynamic index, which now has a much simpler job
- no partitioning of symbols by file to avoid duplication of header symbols
- no reindexing of edited files
- only a single worker thread
- compilation database is slurped synchronously (doesn't scale)
- uses memindex, rebuilds after every file (should be dex, periodically)
It's not hooked up to ClangdServer/ClangdLSPServer yet: the layering
isn't clear (it should really be in ClangdServer, but ClangdLSPServer
has all the CDB interactions).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, jfb, cfe-commits
Differential Revision: https://reviews.llvm.org/D53032
llvm-svn: 344513
2018-10-15 21:34:10 +08:00
|
|
|
|
|
|
|
BackgroundIndex::~BackgroundIndex() {
|
|
|
|
stop();
|
2018-10-30 20:13:27 +08:00
|
|
|
for (auto &Thread : ThreadPool)
|
|
|
|
Thread.join();
|
[clangd] Minimal implementation of automatic static index (not enabled).
Summary:
See tinyurl.com/clangd-automatic-index for design and goals.
Lots of limitations to keep this patch smallish, TODOs everywhere:
- no serialization to disk
- no changes to dynamic index, which now has a much simpler job
- no partitioning of symbols by file to avoid duplication of header symbols
- no reindexing of edited files
- only a single worker thread
- compilation database is slurped synchronously (doesn't scale)
- uses memindex, rebuilds after every file (should be dex, periodically)
It's not hooked up to ClangdServer/ClangdLSPServer yet: the layering
isn't clear (it should really be in ClangdServer, but ClangdLSPServer
has all the CDB interactions).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, jfb, cfe-commits
Differential Revision: https://reviews.llvm.org/D53032
llvm-svn: 344513
2018-10-15 21:34:10 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void BackgroundIndex::stop() {
|
|
|
|
{
|
2018-12-18 23:39:33 +08:00
|
|
|
std::lock_guard<std::mutex> QueueLock(QueueMu);
|
|
|
|
std::lock_guard<std::mutex> IndexLock(IndexMu);
|
[clangd] Minimal implementation of automatic static index (not enabled).
Summary:
See tinyurl.com/clangd-automatic-index for design and goals.
Lots of limitations to keep this patch smallish, TODOs everywhere:
- no serialization to disk
- no changes to dynamic index, which now has a much simpler job
- no partitioning of symbols by file to avoid duplication of header symbols
- no reindexing of edited files
- only a single worker thread
- compilation database is slurped synchronously (doesn't scale)
- uses memindex, rebuilds after every file (should be dex, periodically)
It's not hooked up to ClangdServer/ClangdLSPServer yet: the layering
isn't clear (it should really be in ClangdServer, but ClangdLSPServer
has all the CDB interactions).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, jfb, cfe-commits
Differential Revision: https://reviews.llvm.org/D53032
llvm-svn: 344513
2018-10-15 21:34:10 +08:00
|
|
|
ShouldStop = true;
|
|
|
|
}
|
|
|
|
QueueCV.notify_all();
|
2018-12-18 23:39:33 +08:00
|
|
|
IndexCV.notify_all();
|
[clangd] Minimal implementation of automatic static index (not enabled).
Summary:
See tinyurl.com/clangd-automatic-index for design and goals.
Lots of limitations to keep this patch smallish, TODOs everywhere:
- no serialization to disk
- no changes to dynamic index, which now has a much simpler job
- no partitioning of symbols by file to avoid duplication of header symbols
- no reindexing of edited files
- only a single worker thread
- compilation database is slurped synchronously (doesn't scale)
- uses memindex, rebuilds after every file (should be dex, periodically)
It's not hooked up to ClangdServer/ClangdLSPServer yet: the layering
isn't clear (it should really be in ClangdServer, but ClangdLSPServer
has all the CDB interactions).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, jfb, cfe-commits
Differential Revision: https://reviews.llvm.org/D53032
llvm-svn: 344513
2018-10-15 21:34:10 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void BackgroundIndex::run() {
|
2018-10-30 20:13:27 +08:00
|
|
|
WithContext Background(BackgroundContext.clone());
|
[clangd] Minimal implementation of automatic static index (not enabled).
Summary:
See tinyurl.com/clangd-automatic-index for design and goals.
Lots of limitations to keep this patch smallish, TODOs everywhere:
- no serialization to disk
- no changes to dynamic index, which now has a much simpler job
- no partitioning of symbols by file to avoid duplication of header symbols
- no reindexing of edited files
- only a single worker thread
- compilation database is slurped synchronously (doesn't scale)
- uses memindex, rebuilds after every file (should be dex, periodically)
It's not hooked up to ClangdServer/ClangdLSPServer yet: the layering
isn't clear (it should really be in ClangdServer, but ClangdLSPServer
has all the CDB interactions).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, jfb, cfe-commits
Differential Revision: https://reviews.llvm.org/D53032
llvm-svn: 344513
2018-10-15 21:34:10 +08:00
|
|
|
while (true) {
|
2019-01-07 23:45:19 +08:00
|
|
|
llvm::Optional<Task> Task;
|
2018-12-17 20:30:27 +08:00
|
|
|
ThreadPriority Priority;
|
[clangd] Minimal implementation of automatic static index (not enabled).
Summary:
See tinyurl.com/clangd-automatic-index for design and goals.
Lots of limitations to keep this patch smallish, TODOs everywhere:
- no serialization to disk
- no changes to dynamic index, which now has a much simpler job
- no partitioning of symbols by file to avoid duplication of header symbols
- no reindexing of edited files
- only a single worker thread
- compilation database is slurped synchronously (doesn't scale)
- uses memindex, rebuilds after every file (should be dex, periodically)
It's not hooked up to ClangdServer/ClangdLSPServer yet: the layering
isn't clear (it should really be in ClangdServer, but ClangdLSPServer
has all the CDB interactions).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, jfb, cfe-commits
Differential Revision: https://reviews.llvm.org/D53032
llvm-svn: 344513
2018-10-15 21:34:10 +08:00
|
|
|
{
|
|
|
|
std::unique_lock<std::mutex> Lock(QueueMu);
|
|
|
|
QueueCV.wait(Lock, [&] { return ShouldStop || !Queue.empty(); });
|
|
|
|
if (ShouldStop) {
|
|
|
|
Queue.clear();
|
|
|
|
QueueCV.notify_all();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
++NumActiveTasks;
|
2018-12-17 20:30:27 +08:00
|
|
|
std::tie(Task, Priority) = std::move(Queue.front());
|
[clangd] Minimal implementation of automatic static index (not enabled).
Summary:
See tinyurl.com/clangd-automatic-index for design and goals.
Lots of limitations to keep this patch smallish, TODOs everywhere:
- no serialization to disk
- no changes to dynamic index, which now has a much simpler job
- no partitioning of symbols by file to avoid duplication of header symbols
- no reindexing of edited files
- only a single worker thread
- compilation database is slurped synchronously (doesn't scale)
- uses memindex, rebuilds after every file (should be dex, periodically)
It's not hooked up to ClangdServer/ClangdLSPServer yet: the layering
isn't clear (it should really be in ClangdServer, but ClangdLSPServer
has all the CDB interactions).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, jfb, cfe-commits
Differential Revision: https://reviews.llvm.org/D53032
llvm-svn: 344513
2018-10-15 21:34:10 +08:00
|
|
|
Queue.pop_front();
|
|
|
|
}
|
2018-12-17 20:30:27 +08:00
|
|
|
|
|
|
|
if (Priority != ThreadPriority::Normal)
|
|
|
|
setCurrentThreadPriority(Priority);
|
[clangd] Minimal implementation of automatic static index (not enabled).
Summary:
See tinyurl.com/clangd-automatic-index for design and goals.
Lots of limitations to keep this patch smallish, TODOs everywhere:
- no serialization to disk
- no changes to dynamic index, which now has a much simpler job
- no partitioning of symbols by file to avoid duplication of header symbols
- no reindexing of edited files
- only a single worker thread
- compilation database is slurped synchronously (doesn't scale)
- uses memindex, rebuilds after every file (should be dex, periodically)
It's not hooked up to ClangdServer/ClangdLSPServer yet: the layering
isn't clear (it should really be in ClangdServer, but ClangdLSPServer
has all the CDB interactions).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, jfb, cfe-commits
Differential Revision: https://reviews.llvm.org/D53032
llvm-svn: 344513
2018-10-15 21:34:10 +08:00
|
|
|
(*Task)();
|
2018-12-17 20:30:27 +08:00
|
|
|
if (Priority != ThreadPriority::Normal)
|
|
|
|
setCurrentThreadPriority(ThreadPriority::Normal);
|
|
|
|
|
[clangd] Minimal implementation of automatic static index (not enabled).
Summary:
See tinyurl.com/clangd-automatic-index for design and goals.
Lots of limitations to keep this patch smallish, TODOs everywhere:
- no serialization to disk
- no changes to dynamic index, which now has a much simpler job
- no partitioning of symbols by file to avoid duplication of header symbols
- no reindexing of edited files
- only a single worker thread
- compilation database is slurped synchronously (doesn't scale)
- uses memindex, rebuilds after every file (should be dex, periodically)
It's not hooked up to ClangdServer/ClangdLSPServer yet: the layering
isn't clear (it should really be in ClangdServer, but ClangdLSPServer
has all the CDB interactions).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, jfb, cfe-commits
Differential Revision: https://reviews.llvm.org/D53032
llvm-svn: 344513
2018-10-15 21:34:10 +08:00
|
|
|
{
|
|
|
|
std::unique_lock<std::mutex> Lock(QueueMu);
|
|
|
|
assert(NumActiveTasks > 0 && "before decrementing");
|
|
|
|
--NumActiveTasks;
|
|
|
|
}
|
|
|
|
QueueCV.notify_all();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
[clangd] Enable auto-index behind a flag.
Summary:
Ownership and configuration:
The auto-index (background index) is maintained by ClangdServer, like Dynamic.
(This means ClangdServer will be able to enqueue preamble indexing in future).
For now it's enabled by a simple boolean flag in ClangdServer::Options, but
we probably want to eventually allow injecting the storage strategy.
New 'sync' command:
In order to meaningfully test the integration (not just unit-test components)
we need a way for tests to ensure the asynchronous index reads/writes occur
before a certain point.
Because these tests and assertions are few, I think exposing an explicit "sync"
command for use in tests is simpler than allowing threading to be completely
disabled in the background index (as we do for TUScheduler).
Bugs:
I fixed a couple of trivial bugs I found while testing, but there's one I can't.
JSONCompilationDatabase::getAllFiles() may return relative paths, and currently
we trigger an assertion that assumes they are absolute.
There's no efficient way to resolve them (you have to retrieve the corresponding
command and then resolve against its directory property). In general I think
this behavior is broken and we should fix it in JSONCompilationDatabase and
require CompilationDatabase::getAllFiles() to be absolute.
Reviewers: kadircet
Subscribers: ilya-biryukov, ioeric, MaskRay, jkorous, arphaman, cfe-commits
Differential Revision: https://reviews.llvm.org/D54894
llvm-svn: 347567
2018-11-27 00:00:11 +08:00
|
|
|
bool BackgroundIndex::blockUntilIdleForTest(
|
|
|
|
llvm::Optional<double> TimeoutSeconds) {
|
[clangd] Minimal implementation of automatic static index (not enabled).
Summary:
See tinyurl.com/clangd-automatic-index for design and goals.
Lots of limitations to keep this patch smallish, TODOs everywhere:
- no serialization to disk
- no changes to dynamic index, which now has a much simpler job
- no partitioning of symbols by file to avoid duplication of header symbols
- no reindexing of edited files
- only a single worker thread
- compilation database is slurped synchronously (doesn't scale)
- uses memindex, rebuilds after every file (should be dex, periodically)
It's not hooked up to ClangdServer/ClangdLSPServer yet: the layering
isn't clear (it should really be in ClangdServer, but ClangdLSPServer
has all the CDB interactions).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, jfb, cfe-commits
Differential Revision: https://reviews.llvm.org/D53032
llvm-svn: 344513
2018-10-15 21:34:10 +08:00
|
|
|
std::unique_lock<std::mutex> Lock(QueueMu);
|
[clangd] Enable auto-index behind a flag.
Summary:
Ownership and configuration:
The auto-index (background index) is maintained by ClangdServer, like Dynamic.
(This means ClangdServer will be able to enqueue preamble indexing in future).
For now it's enabled by a simple boolean flag in ClangdServer::Options, but
we probably want to eventually allow injecting the storage strategy.
New 'sync' command:
In order to meaningfully test the integration (not just unit-test components)
we need a way for tests to ensure the asynchronous index reads/writes occur
before a certain point.
Because these tests and assertions are few, I think exposing an explicit "sync"
command for use in tests is simpler than allowing threading to be completely
disabled in the background index (as we do for TUScheduler).
Bugs:
I fixed a couple of trivial bugs I found while testing, but there's one I can't.
JSONCompilationDatabase::getAllFiles() may return relative paths, and currently
we trigger an assertion that assumes they are absolute.
There's no efficient way to resolve them (you have to retrieve the corresponding
command and then resolve against its directory property). In general I think
this behavior is broken and we should fix it in JSONCompilationDatabase and
require CompilationDatabase::getAllFiles() to be absolute.
Reviewers: kadircet
Subscribers: ilya-biryukov, ioeric, MaskRay, jkorous, arphaman, cfe-commits
Differential Revision: https://reviews.llvm.org/D54894
llvm-svn: 347567
2018-11-27 00:00:11 +08:00
|
|
|
return wait(Lock, QueueCV, timeoutSeconds(TimeoutSeconds),
|
|
|
|
[&] { return Queue.empty() && NumActiveTasks == 0; });
|
[clangd] Minimal implementation of automatic static index (not enabled).
Summary:
See tinyurl.com/clangd-automatic-index for design and goals.
Lots of limitations to keep this patch smallish, TODOs everywhere:
- no serialization to disk
- no changes to dynamic index, which now has a much simpler job
- no partitioning of symbols by file to avoid duplication of header symbols
- no reindexing of edited files
- only a single worker thread
- compilation database is slurped synchronously (doesn't scale)
- uses memindex, rebuilds after every file (should be dex, periodically)
It's not hooked up to ClangdServer/ClangdLSPServer yet: the layering
isn't clear (it should really be in ClangdServer, but ClangdLSPServer
has all the CDB interactions).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, jfb, cfe-commits
Differential Revision: https://reviews.llvm.org/D53032
llvm-svn: 344513
2018-10-15 21:34:10 +08:00
|
|
|
}
|
|
|
|
|
[clangd] Auto-index watches global CDB for changes.
Summary:
Instead of receiving compilation commands, auto-index is triggered by just
filenames to reindex, and gets commands from the global comp DB internally.
This has advantages:
- more of the work can be done asynchronously (fetching compilation commands
upfront can be slow for large CDBs)
- we get access to the CDB which can be used to retrieve interpolated commands
for headers (useful in some cases where the original TU goes away)
- fits nicely with the filename-only change observation from r347297
The interface to GlobalCompilationDatabase gets extended: when retrieving a
compile command, the GCDB can optionally report the project the file belongs to.
This naturally fits together with getCompileCommand: it's hard to implement one
without the other. But because most callers don't care, I've ended up with an
awkward optional-out-param-in-virtual method pattern - maybe there's a better
one.
This is the main missing integration point between ClangdServer and
BackgroundIndex, after this we should be able to add an auto-index flag.
Reviewers: ioeric, kadircet
Subscribers: MaskRay, jkorous, arphaman, cfe-commits, ilya-biryukov
Differential Revision: https://reviews.llvm.org/D54865
llvm-svn: 347538
2018-11-26 17:51:50 +08:00
|
|
|
void BackgroundIndex::enqueue(const std::vector<std::string> &ChangedFiles) {
|
2018-12-17 20:30:27 +08:00
|
|
|
enqueueTask(
|
|
|
|
[this, ChangedFiles] {
|
|
|
|
trace::Span Tracer("BackgroundIndexEnqueue");
|
|
|
|
// We're doing this asynchronously, because we'll read shards here too.
|
|
|
|
log("Enqueueing {0} commands for indexing", ChangedFiles.size());
|
|
|
|
SPAN_ATTACH(Tracer, "files", int64_t(ChangedFiles.size()));
|
[clangd] Auto-index watches global CDB for changes.
Summary:
Instead of receiving compilation commands, auto-index is triggered by just
filenames to reindex, and gets commands from the global comp DB internally.
This has advantages:
- more of the work can be done asynchronously (fetching compilation commands
upfront can be slow for large CDBs)
- we get access to the CDB which can be used to retrieve interpolated commands
for headers (useful in some cases where the original TU goes away)
- fits nicely with the filename-only change observation from r347297
The interface to GlobalCompilationDatabase gets extended: when retrieving a
compile command, the GCDB can optionally report the project the file belongs to.
This naturally fits together with getCompileCommand: it's hard to implement one
without the other. But because most callers don't care, I've ended up with an
awkward optional-out-param-in-virtual method pattern - maybe there's a better
one.
This is the main missing integration point between ClangdServer and
BackgroundIndex, after this we should be able to add an auto-index flag.
Reviewers: ioeric, kadircet
Subscribers: MaskRay, jkorous, arphaman, cfe-commits, ilya-biryukov
Differential Revision: https://reviews.llvm.org/D54865
llvm-svn: 347538
2018-11-26 17:51:50 +08:00
|
|
|
|
2019-01-11 01:03:04 +08:00
|
|
|
auto NeedsReIndexing = loadShards(std::move(ChangedFiles));
|
|
|
|
// Run indexing for files that need to be updated.
|
|
|
|
std::shuffle(NeedsReIndexing.begin(), NeedsReIndexing.end(),
|
|
|
|
std::mt19937(std::random_device{}()));
|
|
|
|
for (auto &Elem : NeedsReIndexing)
|
|
|
|
enqueue(std::move(Elem.first), Elem.second);
|
2018-12-17 20:30:27 +08:00
|
|
|
},
|
|
|
|
ThreadPriority::Normal);
|
[clangd] Auto-index watches global CDB for changes.
Summary:
Instead of receiving compilation commands, auto-index is triggered by just
filenames to reindex, and gets commands from the global comp DB internally.
This has advantages:
- more of the work can be done asynchronously (fetching compilation commands
upfront can be slow for large CDBs)
- we get access to the CDB which can be used to retrieve interpolated commands
for headers (useful in some cases where the original TU goes away)
- fits nicely with the filename-only change observation from r347297
The interface to GlobalCompilationDatabase gets extended: when retrieving a
compile command, the GCDB can optionally report the project the file belongs to.
This naturally fits together with getCompileCommand: it's hard to implement one
without the other. But because most callers don't care, I've ended up with an
awkward optional-out-param-in-virtual method pattern - maybe there's a better
one.
This is the main missing integration point between ClangdServer and
BackgroundIndex, after this we should be able to add an auto-index flag.
Reviewers: ioeric, kadircet
Subscribers: MaskRay, jkorous, arphaman, cfe-commits, ilya-biryukov
Differential Revision: https://reviews.llvm.org/D54865
llvm-svn: 347538
2018-11-26 17:51:50 +08:00
|
|
|
}
|
|
|
|
|
2019-01-11 01:03:04 +08:00
|
|
|
void BackgroundIndex::enqueue(tooling::CompileCommand Cmd,
|
|
|
|
BackgroundIndexStorage *Storage) {
|
|
|
|
enqueueTask(Bind(
|
|
|
|
[this, Storage](tooling::CompileCommand Cmd) {
|
|
|
|
Cmd.CommandLine.push_back("-resource-dir=" + ResourceDir);
|
|
|
|
// We can't use llvm::StringRef here since we are going to
|
|
|
|
// move from Cmd during the call below.
|
|
|
|
const std::string FileName = Cmd.Filename;
|
|
|
|
if (auto Error = index(std::move(Cmd), Storage))
|
|
|
|
elog("Indexing {0} failed: {1}", FileName,
|
|
|
|
std::move(Error));
|
|
|
|
},
|
|
|
|
std::move(Cmd)),
|
|
|
|
ThreadPriority::Low);
|
[clangd] Minimal implementation of automatic static index (not enabled).
Summary:
See tinyurl.com/clangd-automatic-index for design and goals.
Lots of limitations to keep this patch smallish, TODOs everywhere:
- no serialization to disk
- no changes to dynamic index, which now has a much simpler job
- no partitioning of symbols by file to avoid duplication of header symbols
- no reindexing of edited files
- only a single worker thread
- compilation database is slurped synchronously (doesn't scale)
- uses memindex, rebuilds after every file (should be dex, periodically)
It's not hooked up to ClangdServer/ClangdLSPServer yet: the layering
isn't clear (it should really be in ClangdServer, but ClangdLSPServer
has all the CDB interactions).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, jfb, cfe-commits
Differential Revision: https://reviews.llvm.org/D53032
llvm-svn: 344513
2018-10-15 21:34:10 +08:00
|
|
|
}
|
|
|
|
|
2018-12-17 20:30:27 +08:00
|
|
|
void BackgroundIndex::enqueueTask(Task T, ThreadPriority Priority) {
|
[clangd] Minimal implementation of automatic static index (not enabled).
Summary:
See tinyurl.com/clangd-automatic-index for design and goals.
Lots of limitations to keep this patch smallish, TODOs everywhere:
- no serialization to disk
- no changes to dynamic index, which now has a much simpler job
- no partitioning of symbols by file to avoid duplication of header symbols
- no reindexing of edited files
- only a single worker thread
- compilation database is slurped synchronously (doesn't scale)
- uses memindex, rebuilds after every file (should be dex, periodically)
It's not hooked up to ClangdServer/ClangdLSPServer yet: the layering
isn't clear (it should really be in ClangdServer, but ClangdLSPServer
has all the CDB interactions).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, jfb, cfe-commits
Differential Revision: https://reviews.llvm.org/D53032
llvm-svn: 344513
2018-10-15 21:34:10 +08:00
|
|
|
{
|
|
|
|
std::lock_guard<std::mutex> Lock(QueueMu);
|
2018-12-17 20:30:27 +08:00
|
|
|
auto I = Queue.end();
|
|
|
|
// We first store the tasks with Normal priority in the front of the queue.
|
|
|
|
// Then we store low priority tasks. Normal priority tasks are pretty rare,
|
|
|
|
// they should not grow beyond single-digit numbers, so it is OK to do
|
|
|
|
// linear search and insert after that.
|
|
|
|
if (Priority == ThreadPriority::Normal) {
|
|
|
|
I = llvm::find_if(Queue, [](const std::pair<Task, ThreadPriority> &Elem) {
|
|
|
|
return Elem.second == ThreadPriority::Low;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
Queue.insert(I, {std::move(T), Priority});
|
[clangd] Minimal implementation of automatic static index (not enabled).
Summary:
See tinyurl.com/clangd-automatic-index for design and goals.
Lots of limitations to keep this patch smallish, TODOs everywhere:
- no serialization to disk
- no changes to dynamic index, which now has a much simpler job
- no partitioning of symbols by file to avoid duplication of header symbols
- no reindexing of edited files
- only a single worker thread
- compilation database is slurped synchronously (doesn't scale)
- uses memindex, rebuilds after every file (should be dex, periodically)
It's not hooked up to ClangdServer/ClangdLSPServer yet: the layering
isn't clear (it should really be in ClangdServer, but ClangdLSPServer
has all the CDB interactions).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, jfb, cfe-commits
Differential Revision: https://reviews.llvm.org/D53032
llvm-svn: 344513
2018-10-15 21:34:10 +08:00
|
|
|
}
|
|
|
|
QueueCV.notify_all();
|
|
|
|
}
|
|
|
|
|
2019-01-15 17:03:33 +08:00
|
|
|
/// Given index results from a TU, only update symbols coming from files that
|
|
|
|
/// are different or missing from than \p DigestsSnapshot. Also stores new index
|
|
|
|
/// information on IndexStorage.
|
2019-01-07 23:45:19 +08:00
|
|
|
void BackgroundIndex::update(llvm::StringRef MainFile, IndexFileIn Index,
|
2019-01-15 17:03:33 +08:00
|
|
|
const llvm::StringMap<FileDigest> &DigestsSnapshot,
|
2018-11-16 17:03:56 +08:00
|
|
|
BackgroundIndexStorage *IndexStorage) {
|
2018-11-06 18:55:21 +08:00
|
|
|
// Partition symbols/references into files.
|
|
|
|
struct File {
|
2019-01-07 23:45:19 +08:00
|
|
|
llvm::DenseSet<const Symbol *> Symbols;
|
|
|
|
llvm::DenseSet<const Ref *> Refs;
|
2019-01-15 17:03:33 +08:00
|
|
|
FileDigest Digest;
|
2018-11-06 18:55:21 +08:00
|
|
|
};
|
2019-01-07 23:45:19 +08:00
|
|
|
llvm::StringMap<File> Files;
|
2018-11-06 18:55:21 +08:00
|
|
|
URIToFileCache URICache(MainFile);
|
2019-01-15 17:03:33 +08:00
|
|
|
for (const auto &IndexIt : *Index.Sources) {
|
|
|
|
const auto &IGN = IndexIt.getValue();
|
|
|
|
const auto AbsPath = URICache.resolve(IGN.URI);
|
|
|
|
const auto DigestIt = DigestsSnapshot.find(AbsPath);
|
|
|
|
// File has different contents.
|
|
|
|
if (DigestIt == DigestsSnapshot.end() || DigestIt->getValue() != IGN.Digest)
|
|
|
|
Files.try_emplace(AbsPath).first->getValue().Digest = IGN.Digest;
|
|
|
|
}
|
2018-11-28 00:08:53 +08:00
|
|
|
for (const auto &Sym : *Index.Symbols) {
|
2018-11-06 18:55:21 +08:00
|
|
|
if (Sym.CanonicalDeclaration) {
|
|
|
|
auto DeclPath = URICache.resolve(Sym.CanonicalDeclaration.FileURI);
|
2019-01-15 17:03:33 +08:00
|
|
|
const auto FileIt = Files.find(DeclPath);
|
|
|
|
if (FileIt != Files.end())
|
|
|
|
FileIt->second.Symbols.insert(&Sym);
|
2018-11-06 18:55:21 +08:00
|
|
|
}
|
|
|
|
// For symbols with different declaration and definition locations, we store
|
|
|
|
// the full symbol in both the header file and the implementation file, so
|
|
|
|
// that merging can tell the preferred symbols (from canonical headers) from
|
|
|
|
// other symbols (e.g. forward declarations).
|
|
|
|
if (Sym.Definition &&
|
|
|
|
Sym.Definition.FileURI != Sym.CanonicalDeclaration.FileURI) {
|
|
|
|
auto DefPath = URICache.resolve(Sym.Definition.FileURI);
|
2019-01-15 17:03:33 +08:00
|
|
|
const auto FileIt = Files.find(DefPath);
|
|
|
|
if (FileIt != Files.end())
|
|
|
|
FileIt->second.Symbols.insert(&Sym);
|
2018-11-06 18:55:21 +08:00
|
|
|
}
|
|
|
|
}
|
2019-01-07 23:45:19 +08:00
|
|
|
llvm::DenseMap<const Ref *, SymbolID> RefToIDs;
|
2018-11-28 00:08:53 +08:00
|
|
|
for (const auto &SymRefs : *Index.Refs) {
|
2018-11-06 18:55:21 +08:00
|
|
|
for (const auto &R : SymRefs.second) {
|
|
|
|
auto Path = URICache.resolve(R.Location.FileURI);
|
2019-01-15 17:03:33 +08:00
|
|
|
const auto FileIt = Files.find(Path);
|
|
|
|
if (FileIt != Files.end()) {
|
|
|
|
auto &F = FileIt->getValue();
|
2018-11-06 18:55:21 +08:00
|
|
|
RefToIDs[&R] = SymRefs.first;
|
|
|
|
F.Refs.insert(&R);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Build and store new slabs for each updated file.
|
2019-01-15 17:03:33 +08:00
|
|
|
for (const auto &FileIt : Files) {
|
|
|
|
llvm::StringRef Path = FileIt.getKey();
|
2018-11-06 18:55:21 +08:00
|
|
|
SymbolSlab::Builder Syms;
|
|
|
|
RefSlab::Builder Refs;
|
2019-01-15 17:03:33 +08:00
|
|
|
for (const auto *S : FileIt.second.Symbols)
|
|
|
|
Syms.insert(*S);
|
|
|
|
for (const auto *R : FileIt.second.Refs)
|
|
|
|
Refs.insert(RefToIDs[R], *R);
|
2018-11-16 17:03:56 +08:00
|
|
|
auto SS = llvm::make_unique<SymbolSlab>(std::move(Syms).build());
|
|
|
|
auto RS = llvm::make_unique<RefSlab>(std::move(Refs).build());
|
2018-12-04 19:31:57 +08:00
|
|
|
auto IG = llvm::make_unique<IncludeGraph>(
|
|
|
|
getSubGraph(URI::create(Path), Index.Sources.getValue()));
|
2018-11-16 17:03:56 +08:00
|
|
|
// We need to store shards before updating the index, since the latter
|
|
|
|
// consumes slabs.
|
|
|
|
if (IndexStorage) {
|
|
|
|
IndexFileOut Shard;
|
|
|
|
Shard.Symbols = SS.get();
|
|
|
|
Shard.Refs = RS.get();
|
2018-12-04 19:31:57 +08:00
|
|
|
Shard.Sources = IG.get();
|
2018-11-28 00:08:53 +08:00
|
|
|
|
2018-11-16 17:03:56 +08:00
|
|
|
if (auto Error = IndexStorage->storeShard(Path, Shard))
|
|
|
|
elog("Failed to write background-index shard for file {0}: {1}", Path,
|
|
|
|
std::move(Error));
|
|
|
|
}
|
2019-01-11 01:03:04 +08:00
|
|
|
{
|
|
|
|
std::lock_guard<std::mutex> Lock(DigestsMu);
|
2019-01-15 17:03:33 +08:00
|
|
|
auto Hash = FileIt.second.Digest;
|
2019-01-11 01:03:04 +08:00
|
|
|
// Skip if file is already up to date.
|
|
|
|
auto DigestIt = IndexedFileDigests.try_emplace(Path);
|
|
|
|
if (!DigestIt.second && DigestIt.first->second == Hash)
|
|
|
|
continue;
|
|
|
|
DigestIt.first->second = Hash;
|
|
|
|
// This can override a newer version that is added in another thread, if
|
|
|
|
// this thread sees the older version but finishes later. This should be
|
|
|
|
// rare in practice.
|
|
|
|
IndexedSymbols.update(Path, std::move(SS), std::move(RS));
|
|
|
|
}
|
2018-11-06 18:55:21 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-18 23:39:33 +08:00
|
|
|
void BackgroundIndex::buildIndex() {
|
|
|
|
assert(BuildIndexPeriodMs > 0);
|
|
|
|
while (true) {
|
|
|
|
{
|
|
|
|
std::unique_lock<std::mutex> Lock(IndexMu);
|
2019-01-11 01:03:04 +08:00
|
|
|
if (ShouldStop) // Avoid waiting if stopped.
|
2018-12-18 23:39:33 +08:00
|
|
|
break;
|
|
|
|
// Wait until this is notified to stop or `BuildIndexPeriodMs` has past.
|
|
|
|
IndexCV.wait_for(Lock, std::chrono::milliseconds(BuildIndexPeriodMs));
|
2019-01-11 01:03:04 +08:00
|
|
|
if (ShouldStop) // Avoid rebuilding index if stopped.
|
2018-12-18 23:39:33 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!SymbolsUpdatedSinceLastIndex.exchange(false))
|
|
|
|
continue;
|
|
|
|
// There can be symbol update right after the flag is reset above and before
|
|
|
|
// index is rebuilt below. The new index would contain the updated symbols
|
|
|
|
// but the flag would still be true. This is fine as we would simply run an
|
|
|
|
// extra index build.
|
|
|
|
reset(
|
|
|
|
IndexedSymbols.buildIndex(IndexType::Heavy, DuplicateHandling::Merge));
|
|
|
|
log("BackgroundIndex: rebuilt symbol index.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-07 23:45:19 +08:00
|
|
|
llvm::Error BackgroundIndex::index(tooling::CompileCommand Cmd,
|
|
|
|
BackgroundIndexStorage *IndexStorage) {
|
[clangd] Minimal implementation of automatic static index (not enabled).
Summary:
See tinyurl.com/clangd-automatic-index for design and goals.
Lots of limitations to keep this patch smallish, TODOs everywhere:
- no serialization to disk
- no changes to dynamic index, which now has a much simpler job
- no partitioning of symbols by file to avoid duplication of header symbols
- no reindexing of edited files
- only a single worker thread
- compilation database is slurped synchronously (doesn't scale)
- uses memindex, rebuilds after every file (should be dex, periodically)
It's not hooked up to ClangdServer/ClangdLSPServer yet: the layering
isn't clear (it should really be in ClangdServer, but ClangdLSPServer
has all the CDB interactions).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, jfb, cfe-commits
Differential Revision: https://reviews.llvm.org/D53032
llvm-svn: 344513
2018-10-15 21:34:10 +08:00
|
|
|
trace::Span Tracer("BackgroundIndex");
|
|
|
|
SPAN_ATTACH(Tracer, "file", Cmd.Filename);
|
2019-01-11 01:03:04 +08:00
|
|
|
auto AbsolutePath = getAbsolutePath(Cmd);
|
[clangd] Minimal implementation of automatic static index (not enabled).
Summary:
See tinyurl.com/clangd-automatic-index for design and goals.
Lots of limitations to keep this patch smallish, TODOs everywhere:
- no serialization to disk
- no changes to dynamic index, which now has a much simpler job
- no partitioning of symbols by file to avoid duplication of header symbols
- no reindexing of edited files
- only a single worker thread
- compilation database is slurped synchronously (doesn't scale)
- uses memindex, rebuilds after every file (should be dex, periodically)
It's not hooked up to ClangdServer/ClangdLSPServer yet: the layering
isn't clear (it should really be in ClangdServer, but ClangdLSPServer
has all the CDB interactions).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, jfb, cfe-commits
Differential Revision: https://reviews.llvm.org/D53032
llvm-svn: 344513
2018-10-15 21:34:10 +08:00
|
|
|
|
|
|
|
auto FS = FSProvider.getFileSystem();
|
|
|
|
auto Buf = FS->getBufferForFile(AbsolutePath);
|
|
|
|
if (!Buf)
|
2019-01-07 23:45:19 +08:00
|
|
|
return llvm::errorCodeToError(Buf.getError());
|
2018-11-06 18:55:21 +08:00
|
|
|
auto Hash = digest(Buf->get()->getBuffer());
|
|
|
|
|
|
|
|
// Take a snapshot of the digests to avoid locking for each file in the TU.
|
|
|
|
llvm::StringMap<FileDigest> DigestsSnapshot;
|
|
|
|
{
|
|
|
|
std::lock_guard<std::mutex> Lock(DigestsMu);
|
|
|
|
DigestsSnapshot = IndexedFileDigests;
|
[clangd] Minimal implementation of automatic static index (not enabled).
Summary:
See tinyurl.com/clangd-automatic-index for design and goals.
Lots of limitations to keep this patch smallish, TODOs everywhere:
- no serialization to disk
- no changes to dynamic index, which now has a much simpler job
- no partitioning of symbols by file to avoid duplication of header symbols
- no reindexing of edited files
- only a single worker thread
- compilation database is slurped synchronously (doesn't scale)
- uses memindex, rebuilds after every file (should be dex, periodically)
It's not hooked up to ClangdServer/ClangdLSPServer yet: the layering
isn't clear (it should really be in ClangdServer, but ClangdLSPServer
has all the CDB interactions).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, jfb, cfe-commits
Differential Revision: https://reviews.llvm.org/D53032
llvm-svn: 344513
2018-10-15 21:34:10 +08:00
|
|
|
}
|
|
|
|
|
2019-01-19 01:04:26 +08:00
|
|
|
vlog("Indexing {0} (digest:={1})", Cmd.Filename, llvm::toHex(Hash));
|
[clangd] Minimal implementation of automatic static index (not enabled).
Summary:
See tinyurl.com/clangd-automatic-index for design and goals.
Lots of limitations to keep this patch smallish, TODOs everywhere:
- no serialization to disk
- no changes to dynamic index, which now has a much simpler job
- no partitioning of symbols by file to avoid duplication of header symbols
- no reindexing of edited files
- only a single worker thread
- compilation database is slurped synchronously (doesn't scale)
- uses memindex, rebuilds after every file (should be dex, periodically)
It's not hooked up to ClangdServer/ClangdLSPServer yet: the layering
isn't clear (it should really be in ClangdServer, but ClangdLSPServer
has all the CDB interactions).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, jfb, cfe-commits
Differential Revision: https://reviews.llvm.org/D53032
llvm-svn: 344513
2018-10-15 21:34:10 +08:00
|
|
|
ParseInputs Inputs;
|
|
|
|
Inputs.FS = std::move(FS);
|
|
|
|
Inputs.FS->setCurrentWorkingDirectory(Cmd.Directory);
|
|
|
|
Inputs.CompileCommand = std::move(Cmd);
|
|
|
|
auto CI = buildCompilerInvocation(Inputs);
|
|
|
|
if (!CI)
|
2019-01-07 23:45:19 +08:00
|
|
|
return llvm::createStringError(llvm::inconvertibleErrorCode(),
|
|
|
|
"Couldn't build compiler invocation");
|
[clangd] Minimal implementation of automatic static index (not enabled).
Summary:
See tinyurl.com/clangd-automatic-index for design and goals.
Lots of limitations to keep this patch smallish, TODOs everywhere:
- no serialization to disk
- no changes to dynamic index, which now has a much simpler job
- no partitioning of symbols by file to avoid duplication of header symbols
- no reindexing of edited files
- only a single worker thread
- compilation database is slurped synchronously (doesn't scale)
- uses memindex, rebuilds after every file (should be dex, periodically)
It's not hooked up to ClangdServer/ClangdLSPServer yet: the layering
isn't clear (it should really be in ClangdServer, but ClangdLSPServer
has all the CDB interactions).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, jfb, cfe-commits
Differential Revision: https://reviews.llvm.org/D53032
llvm-svn: 344513
2018-10-15 21:34:10 +08:00
|
|
|
IgnoreDiagnostics IgnoreDiags;
|
|
|
|
auto Clang = prepareCompilerInstance(
|
|
|
|
std::move(CI), /*Preamble=*/nullptr, std::move(*Buf),
|
|
|
|
std::make_shared<PCHContainerOperations>(), Inputs.FS, IgnoreDiags);
|
|
|
|
if (!Clang)
|
2019-01-07 23:45:19 +08:00
|
|
|
return llvm::createStringError(llvm::inconvertibleErrorCode(),
|
|
|
|
"Couldn't build compiler instance");
|
[clangd] Minimal implementation of automatic static index (not enabled).
Summary:
See tinyurl.com/clangd-automatic-index for design and goals.
Lots of limitations to keep this patch smallish, TODOs everywhere:
- no serialization to disk
- no changes to dynamic index, which now has a much simpler job
- no partitioning of symbols by file to avoid duplication of header symbols
- no reindexing of edited files
- only a single worker thread
- compilation database is slurped synchronously (doesn't scale)
- uses memindex, rebuilds after every file (should be dex, periodically)
It's not hooked up to ClangdServer/ClangdLSPServer yet: the layering
isn't clear (it should really be in ClangdServer, but ClangdLSPServer
has all the CDB interactions).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, jfb, cfe-commits
Differential Revision: https://reviews.llvm.org/D53032
llvm-svn: 344513
2018-10-15 21:34:10 +08:00
|
|
|
|
|
|
|
SymbolCollector::Options IndexOpts;
|
2019-01-15 17:03:33 +08:00
|
|
|
IndexOpts.FileFilter = createFileFilter(DigestsSnapshot);
|
2018-12-04 19:31:57 +08:00
|
|
|
IndexFileIn Index;
|
[clangd] Minimal implementation of automatic static index (not enabled).
Summary:
See tinyurl.com/clangd-automatic-index for design and goals.
Lots of limitations to keep this patch smallish, TODOs everywhere:
- no serialization to disk
- no changes to dynamic index, which now has a much simpler job
- no partitioning of symbols by file to avoid duplication of header symbols
- no reindexing of edited files
- only a single worker thread
- compilation database is slurped synchronously (doesn't scale)
- uses memindex, rebuilds after every file (should be dex, periodically)
It's not hooked up to ClangdServer/ClangdLSPServer yet: the layering
isn't clear (it should really be in ClangdServer, but ClangdLSPServer
has all the CDB interactions).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, jfb, cfe-commits
Differential Revision: https://reviews.llvm.org/D53032
llvm-svn: 344513
2018-10-15 21:34:10 +08:00
|
|
|
auto Action = createStaticIndexingAction(
|
2018-12-04 19:31:57 +08:00
|
|
|
IndexOpts, [&](SymbolSlab S) { Index.Symbols = std::move(S); },
|
|
|
|
[&](RefSlab R) { Index.Refs = std::move(R); },
|
|
|
|
[&](IncludeGraph IG) { Index.Sources = std::move(IG); });
|
[clangd] Minimal implementation of automatic static index (not enabled).
Summary:
See tinyurl.com/clangd-automatic-index for design and goals.
Lots of limitations to keep this patch smallish, TODOs everywhere:
- no serialization to disk
- no changes to dynamic index, which now has a much simpler job
- no partitioning of symbols by file to avoid duplication of header symbols
- no reindexing of edited files
- only a single worker thread
- compilation database is slurped synchronously (doesn't scale)
- uses memindex, rebuilds after every file (should be dex, periodically)
It's not hooked up to ClangdServer/ClangdLSPServer yet: the layering
isn't clear (it should really be in ClangdServer, but ClangdLSPServer
has all the CDB interactions).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, jfb, cfe-commits
Differential Revision: https://reviews.llvm.org/D53032
llvm-svn: 344513
2018-10-15 21:34:10 +08:00
|
|
|
|
|
|
|
// We're going to run clang here, and it could potentially crash.
|
|
|
|
// We could use CrashRecoveryContext to try to make indexing crashes nonfatal,
|
|
|
|
// but the leaky "recovery" is pretty scary too in a long-running process.
|
|
|
|
// If crashes are a real problem, maybe we should fork a child process.
|
|
|
|
|
|
|
|
const FrontendInputFile &Input = Clang->getFrontendOpts().Inputs.front();
|
|
|
|
if (!Action->BeginSourceFile(*Clang, Input))
|
2019-01-07 23:45:19 +08:00
|
|
|
return llvm::createStringError(llvm::inconvertibleErrorCode(),
|
|
|
|
"BeginSourceFile() failed");
|
[clangd] Minimal implementation of automatic static index (not enabled).
Summary:
See tinyurl.com/clangd-automatic-index for design and goals.
Lots of limitations to keep this patch smallish, TODOs everywhere:
- no serialization to disk
- no changes to dynamic index, which now has a much simpler job
- no partitioning of symbols by file to avoid duplication of header symbols
- no reindexing of edited files
- only a single worker thread
- compilation database is slurped synchronously (doesn't scale)
- uses memindex, rebuilds after every file (should be dex, periodically)
It's not hooked up to ClangdServer/ClangdLSPServer yet: the layering
isn't clear (it should really be in ClangdServer, but ClangdLSPServer
has all the CDB interactions).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, jfb, cfe-commits
Differential Revision: https://reviews.llvm.org/D53032
llvm-svn: 344513
2018-10-15 21:34:10 +08:00
|
|
|
if (!Action->Execute())
|
2019-01-07 23:45:19 +08:00
|
|
|
return llvm::createStringError(llvm::inconvertibleErrorCode(),
|
|
|
|
"Execute() failed");
|
[clangd] Minimal implementation of automatic static index (not enabled).
Summary:
See tinyurl.com/clangd-automatic-index for design and goals.
Lots of limitations to keep this patch smallish, TODOs everywhere:
- no serialization to disk
- no changes to dynamic index, which now has a much simpler job
- no partitioning of symbols by file to avoid duplication of header symbols
- no reindexing of edited files
- only a single worker thread
- compilation database is slurped synchronously (doesn't scale)
- uses memindex, rebuilds after every file (should be dex, periodically)
It's not hooked up to ClangdServer/ClangdLSPServer yet: the layering
isn't clear (it should really be in ClangdServer, but ClangdLSPServer
has all the CDB interactions).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, jfb, cfe-commits
Differential Revision: https://reviews.llvm.org/D53032
llvm-svn: 344513
2018-10-15 21:34:10 +08:00
|
|
|
Action->EndSourceFile();
|
2018-12-14 20:39:08 +08:00
|
|
|
if (Clang->hasDiagnostics() &&
|
|
|
|
Clang->getDiagnostics().hasUncompilableErrorOccurred()) {
|
2019-01-07 23:45:19 +08:00
|
|
|
return llvm::createStringError(
|
|
|
|
llvm::inconvertibleErrorCode(),
|
|
|
|
"IndexingAction failed: has uncompilable errors");
|
2018-12-14 20:39:08 +08:00
|
|
|
}
|
|
|
|
|
2019-01-11 01:03:04 +08:00
|
|
|
assert(Index.Symbols && Index.Refs && Index.Sources &&
|
|
|
|
"Symbols, Refs and Sources must be set.");
|
[clangd] Minimal implementation of automatic static index (not enabled).
Summary:
See tinyurl.com/clangd-automatic-index for design and goals.
Lots of limitations to keep this patch smallish, TODOs everywhere:
- no serialization to disk
- no changes to dynamic index, which now has a much simpler job
- no partitioning of symbols by file to avoid duplication of header symbols
- no reindexing of edited files
- only a single worker thread
- compilation database is slurped synchronously (doesn't scale)
- uses memindex, rebuilds after every file (should be dex, periodically)
It's not hooked up to ClangdServer/ClangdLSPServer yet: the layering
isn't clear (it should really be in ClangdServer, but ClangdLSPServer
has all the CDB interactions).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, jfb, cfe-commits
Differential Revision: https://reviews.llvm.org/D53032
llvm-svn: 344513
2018-10-15 21:34:10 +08:00
|
|
|
|
2018-12-04 19:31:57 +08:00
|
|
|
log("Indexed {0} ({1} symbols, {2} refs, {3} files)",
|
|
|
|
Inputs.CompileCommand.Filename, Index.Symbols->size(),
|
|
|
|
Index.Refs->numRefs(), Index.Sources->size());
|
|
|
|
SPAN_ATTACH(Tracer, "symbols", int(Index.Symbols->size()));
|
|
|
|
SPAN_ATTACH(Tracer, "refs", int(Index.Refs->numRefs()));
|
|
|
|
SPAN_ATTACH(Tracer, "sources", int(Index.Sources->size()));
|
2018-11-28 00:08:53 +08:00
|
|
|
|
2019-01-15 17:03:33 +08:00
|
|
|
update(AbsolutePath, std::move(Index), DigestsSnapshot, IndexStorage);
|
[clangd] Minimal implementation of automatic static index (not enabled).
Summary:
See tinyurl.com/clangd-automatic-index for design and goals.
Lots of limitations to keep this patch smallish, TODOs everywhere:
- no serialization to disk
- no changes to dynamic index, which now has a much simpler job
- no partitioning of symbols by file to avoid duplication of header symbols
- no reindexing of edited files
- only a single worker thread
- compilation database is slurped synchronously (doesn't scale)
- uses memindex, rebuilds after every file (should be dex, periodically)
It's not hooked up to ClangdServer/ClangdLSPServer yet: the layering
isn't clear (it should really be in ClangdServer, but ClangdLSPServer
has all the CDB interactions).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, jfb, cfe-commits
Differential Revision: https://reviews.llvm.org/D53032
llvm-svn: 344513
2018-10-15 21:34:10 +08:00
|
|
|
|
2018-12-18 23:39:33 +08:00
|
|
|
if (BuildIndexPeriodMs > 0)
|
|
|
|
SymbolsUpdatedSinceLastIndex = true;
|
|
|
|
else
|
|
|
|
reset(
|
|
|
|
IndexedSymbols.buildIndex(IndexType::Light, DuplicateHandling::Merge));
|
2018-11-06 18:55:21 +08:00
|
|
|
|
2019-01-07 23:45:19 +08:00
|
|
|
return llvm::Error::success();
|
[clangd] Minimal implementation of automatic static index (not enabled).
Summary:
See tinyurl.com/clangd-automatic-index for design and goals.
Lots of limitations to keep this patch smallish, TODOs everywhere:
- no serialization to disk
- no changes to dynamic index, which now has a much simpler job
- no partitioning of symbols by file to avoid duplication of header symbols
- no reindexing of edited files
- only a single worker thread
- compilation database is slurped synchronously (doesn't scale)
- uses memindex, rebuilds after every file (should be dex, periodically)
It's not hooked up to ClangdServer/ClangdLSPServer yet: the layering
isn't clear (it should really be in ClangdServer, but ClangdLSPServer
has all the CDB interactions).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, jfb, cfe-commits
Differential Revision: https://reviews.llvm.org/D53032
llvm-svn: 344513
2018-10-15 21:34:10 +08:00
|
|
|
}
|
|
|
|
|
2019-01-11 01:03:04 +08:00
|
|
|
std::vector<BackgroundIndex::Source>
|
|
|
|
BackgroundIndex::loadShard(const tooling::CompileCommand &Cmd,
|
|
|
|
BackgroundIndexStorage *IndexStorage,
|
|
|
|
llvm::StringSet<> &LoadedShards) {
|
|
|
|
struct ShardInfo {
|
|
|
|
std::string AbsolutePath;
|
|
|
|
std::unique_ptr<IndexFileIn> Shard;
|
|
|
|
FileDigest Digest;
|
|
|
|
};
|
|
|
|
std::vector<ShardInfo> IntermediateSymbols;
|
|
|
|
// Make sure we don't have duplicate elements in the queue. Keys are absolute
|
|
|
|
// paths.
|
|
|
|
llvm::StringSet<> InQueue;
|
|
|
|
auto FS = FSProvider.getFileSystem();
|
|
|
|
// Dependencies of this TU, paired with the information about whether they
|
|
|
|
// need to be re-indexed or not.
|
|
|
|
std::vector<Source> Dependencies;
|
2019-01-14 19:24:07 +08:00
|
|
|
std::queue<Source> ToVisit;
|
2019-01-11 01:03:04 +08:00
|
|
|
std::string AbsolutePath = getAbsolutePath(Cmd).str();
|
|
|
|
// Up until we load the shard related to a dependency it needs to be
|
|
|
|
// re-indexed.
|
2019-01-14 19:24:07 +08:00
|
|
|
ToVisit.emplace(AbsolutePath, true);
|
2019-01-11 01:03:04 +08:00
|
|
|
InQueue.insert(AbsolutePath);
|
|
|
|
// Goes over each dependency.
|
2019-01-14 19:24:07 +08:00
|
|
|
while (!ToVisit.empty()) {
|
|
|
|
Dependencies.push_back(std::move(ToVisit.front()));
|
|
|
|
// Dependencies is not modified during the rest of the loop, so it is safe
|
|
|
|
// to keep the reference.
|
|
|
|
auto &CurDependency = Dependencies.back();
|
|
|
|
ToVisit.pop();
|
2019-01-11 01:03:04 +08:00
|
|
|
// If we have already seen this shard before(either loaded or failed) don't
|
|
|
|
// re-try again. Since the information in the shard won't change from one TU
|
|
|
|
// to another.
|
2019-01-14 19:24:07 +08:00
|
|
|
if (!LoadedShards.try_emplace(CurDependency.Path).second) {
|
2019-01-11 01:03:04 +08:00
|
|
|
// If the dependency needs to be re-indexed, first occurence would already
|
|
|
|
// have detected that, so we don't need to issue it again.
|
2019-01-14 19:24:07 +08:00
|
|
|
CurDependency.NeedsReIndexing = false;
|
2019-01-11 01:03:04 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2019-01-14 19:24:07 +08:00
|
|
|
auto Shard = IndexStorage->loadShard(CurDependency.Path);
|
2019-01-11 01:03:04 +08:00
|
|
|
if (!Shard || !Shard->Sources) {
|
|
|
|
// File will be returned as requiring re-indexing to caller.
|
2019-01-14 19:24:07 +08:00
|
|
|
vlog("Failed to load shard: {0}", CurDependency.Path);
|
2019-01-11 01:03:04 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
// These are the edges in the include graph for current dependency.
|
|
|
|
for (const auto &I : *Shard->Sources) {
|
|
|
|
auto U = URI::parse(I.getKey());
|
|
|
|
if (!U)
|
|
|
|
continue;
|
2019-01-14 19:24:07 +08:00
|
|
|
auto AbsolutePath = URI::resolve(*U, CurDependency.Path);
|
2019-01-11 01:03:04 +08:00
|
|
|
if (!AbsolutePath)
|
|
|
|
continue;
|
|
|
|
// Add file as dependency if haven't seen before.
|
|
|
|
if (InQueue.try_emplace(*AbsolutePath).second)
|
2019-01-14 19:24:07 +08:00
|
|
|
ToVisit.emplace(*AbsolutePath, true);
|
2019-01-11 01:03:04 +08:00
|
|
|
// The node contains symbol information only for current file, the rest is
|
|
|
|
// just edges.
|
2019-01-14 19:24:07 +08:00
|
|
|
if (*AbsolutePath != CurDependency.Path)
|
2019-01-11 01:03:04 +08:00
|
|
|
continue;
|
|
|
|
|
|
|
|
// We found source file info for current dependency.
|
|
|
|
assert(I.getValue().Digest != FileDigest{{0}} && "Digest is empty?");
|
|
|
|
ShardInfo SI;
|
2019-01-14 19:24:07 +08:00
|
|
|
SI.AbsolutePath = CurDependency.Path;
|
2019-01-11 01:03:04 +08:00
|
|
|
SI.Shard = std::move(Shard);
|
|
|
|
SI.Digest = I.getValue().Digest;
|
|
|
|
IntermediateSymbols.push_back(std::move(SI));
|
|
|
|
// Check if the source needs re-indexing.
|
|
|
|
// Get the digest, skip it if file doesn't exist.
|
2019-01-14 19:24:07 +08:00
|
|
|
auto Buf = FS->getBufferForFile(CurDependency.Path);
|
2019-01-11 01:03:04 +08:00
|
|
|
if (!Buf) {
|
2019-01-14 19:24:07 +08:00
|
|
|
elog("Couldn't get buffer for file: {0}: {1}", CurDependency.Path,
|
2019-01-11 01:03:04 +08:00
|
|
|
Buf.getError().message());
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
// If digests match then dependency doesn't need re-indexing.
|
2019-01-14 19:24:07 +08:00
|
|
|
CurDependency.NeedsReIndexing =
|
2019-01-11 01:03:04 +08:00
|
|
|
digest(Buf->get()->getBuffer()) != I.getValue().Digest;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Load shard information into background-index.
|
|
|
|
{
|
|
|
|
std::lock_guard<std::mutex> Lock(DigestsMu);
|
|
|
|
// This can override a newer version that is added in another thread,
|
|
|
|
// if this thread sees the older version but finishes later. This
|
|
|
|
// should be rare in practice.
|
|
|
|
for (const ShardInfo &SI : IntermediateSymbols) {
|
|
|
|
auto SS =
|
|
|
|
SI.Shard->Symbols
|
|
|
|
? llvm::make_unique<SymbolSlab>(std::move(*SI.Shard->Symbols))
|
|
|
|
: nullptr;
|
|
|
|
auto RS = SI.Shard->Refs
|
|
|
|
? llvm::make_unique<RefSlab>(std::move(*SI.Shard->Refs))
|
|
|
|
: nullptr;
|
|
|
|
IndexedFileDigests[SI.AbsolutePath] = SI.Digest;
|
|
|
|
IndexedSymbols.update(SI.AbsolutePath, std::move(SS), std::move(RS));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return Dependencies;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Goes over each changed file and loads them from index. Returns the list of
|
|
|
|
// TUs that had out-of-date/no shards.
|
|
|
|
std::vector<std::pair<tooling::CompileCommand, BackgroundIndexStorage *>>
|
|
|
|
BackgroundIndex::loadShards(std::vector<std::string> ChangedFiles) {
|
|
|
|
std::vector<std::pair<tooling::CompileCommand, BackgroundIndexStorage *>>
|
|
|
|
NeedsReIndexing;
|
|
|
|
// Keeps track of the files that will be reindexed, to make sure we won't
|
|
|
|
// re-index same dependencies more than once. Keys are AbsolutePaths.
|
|
|
|
llvm::StringSet<> FilesToIndex;
|
|
|
|
// Keeps track of the loaded shards to make sure we don't perform redundant
|
|
|
|
// disk IO. Keys are absolute paths.
|
|
|
|
llvm::StringSet<> LoadedShards;
|
|
|
|
for (const auto &File : ChangedFiles) {
|
|
|
|
ProjectInfo PI;
|
|
|
|
auto Cmd = CDB.getCompileCommand(File, &PI);
|
|
|
|
if (!Cmd)
|
|
|
|
continue;
|
|
|
|
BackgroundIndexStorage *IndexStorage = IndexStorageFactory(PI.SourceRoot);
|
|
|
|
auto Dependencies = loadShard(*Cmd, IndexStorage, LoadedShards);
|
|
|
|
for (const auto &Dependency : Dependencies) {
|
|
|
|
if (!Dependency.NeedsReIndexing || FilesToIndex.count(Dependency.Path))
|
|
|
|
continue;
|
|
|
|
// FIXME: Currently, we simply schedule indexing on a TU whenever any of
|
|
|
|
// its dependencies needs re-indexing. We might do it smarter by figuring
|
|
|
|
// out a minimal set of TUs that will cover all the stale dependencies.
|
|
|
|
vlog("Enqueueing TU {0} because its dependency {1} needs re-indexing.",
|
|
|
|
Cmd->Filename, Dependency.Path);
|
|
|
|
NeedsReIndexing.push_back({std::move(*Cmd), IndexStorage});
|
|
|
|
// Mark all of this TU's dependencies as to-be-indexed so that we won't
|
|
|
|
// try to re-index those.
|
|
|
|
for (const auto &Dependency : Dependencies)
|
|
|
|
FilesToIndex.insert(Dependency.Path);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
vlog("Loaded all shards");
|
|
|
|
reset(IndexedSymbols.buildIndex(IndexType::Light, DuplicateHandling::Merge));
|
|
|
|
|
|
|
|
return NeedsReIndexing;
|
|
|
|
}
|
|
|
|
|
[clangd] Minimal implementation of automatic static index (not enabled).
Summary:
See tinyurl.com/clangd-automatic-index for design and goals.
Lots of limitations to keep this patch smallish, TODOs everywhere:
- no serialization to disk
- no changes to dynamic index, which now has a much simpler job
- no partitioning of symbols by file to avoid duplication of header symbols
- no reindexing of edited files
- only a single worker thread
- compilation database is slurped synchronously (doesn't scale)
- uses memindex, rebuilds after every file (should be dex, periodically)
It's not hooked up to ClangdServer/ClangdLSPServer yet: the layering
isn't clear (it should really be in ClangdServer, but ClangdLSPServer
has all the CDB interactions).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, jfb, cfe-commits
Differential Revision: https://reviews.llvm.org/D53032
llvm-svn: 344513
2018-10-15 21:34:10 +08:00
|
|
|
} // namespace clangd
|
|
|
|
} // namespace clang
|