//===--- BackgroundIndexRebuild.h - when to rebuild the bg index--*- C++-*-===// // // 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 // //===----------------------------------------------------------------------===// // // This file contains an implementation detail of the background indexer // (Background.h), which is exposed for testing. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_BACKGROUND_INDEX_REBUILD_H #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_BACKGROUND_INDEX_REBUILD_H #include "index/FileIndex.h" #include "index/Index.h" #include "llvm/Support/Threading.h" #include namespace clang { namespace clangd { // The BackgroundIndexRebuilder builds the serving data structures periodically // in response to events in the background indexer. The goal is to ensure the // served data stays fairly fresh, without wasting lots of CPU rebuilding it // often. // // The index is always built after a set of shards are loaded from disk. // This happens when clangd discovers a compilation database that we've // previously built an index for. It's a fairly fast process that yields lots // of data, so we wait to get all of it. // // The index is built after indexing a few translation units, if it wasn't built // already. This ensures quick startup if there's no existing index. // Waiting for a few random TUs yields coverage of the most common headers. // // The index is rebuilt every N TUs, to keep if fresh as files are indexed. // // The index is rebuilt every time the queue goes idle, if it's stale. // // All methods are threadsafe. They're called after FileSymbols is updated // etc. Without external locking, the rebuilt index may include more updates // than intended, which is fine. // // This class is exposed in the header so it can be tested. class BackgroundIndexRebuilder { public: BackgroundIndexRebuilder(SwapIndex *Target, FileSymbols *Source, unsigned Threads) : TUsBeforeFirstBuild(Threads), Target(Target), Source(Source) {} // Called to indicate a TU has been indexed. // May rebuild, if enough TUs have been indexed. void indexedTU(); // Called to indicate that all worker threads are idle. // May reindex, if the index is not up to date. void idle(); // Called to indicate we're going to load a batch of shards from disk. // startLoading() and doneLoading() must be paired, but multiple loading // sessions may happen concurrently. void startLoading(); // Called to indicate some shards were actually loaded from disk. void loadedShard(size_t ShardCount); // Called to indicate we're finished loading shards from disk. // May rebuild (if any were loaded). void doneLoading(); // Ensures we won't start any more rebuilds. void shutdown(); // Thresholds for rebuilding as TUs get indexed. Exposed for testing. const unsigned TUsBeforeFirstBuild; // Typically one per worker thread. const unsigned TUsBeforeRebuild = 100; private: // Run Check under the lock, and rebuild if it returns true. void maybeRebuild(const char *Reason, std::function Check); bool enoughTUsToRebuild() const; // All transient state is guarded by the mutex. std::mutex Mu; bool ShouldStop = false; // Index builds are versioned. ActiveVersion chases StartedVersion. unsigned StartedVersion = 0; unsigned ActiveVersion = 0; // How many TUs have we indexed so far since startup? unsigned IndexedTUs = 0; unsigned IndexedTUsAtLastRebuild = 0; // Are we loading shards? May be multiple concurrent sessions. unsigned Loading = 0; unsigned LoadedShards; // In the current loading session. SwapIndex *Target; FileSymbols *Source; }; } // namespace clangd } // namespace clang #endif