reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
//===-- BackgroundRebuild.cpp - when to rebuild thei background index -----===//
//
// 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
//
//===----------------------------------------------------------------------===//

#include "index/BackgroundRebuild.h"
#include "Compiler.h"
#include "Headers.h"
#include "Logger.h"
#include "ParsedAST.h"
#include "Path.h"
#include "SourceCode.h"
#include "Symbol.h"
#include "Threading.h"
#include "Trace.h"
#include "URI.h"
#include "index/FileIndex.h"
#include "index/IndexAction.h"
#include "index/MemIndex.h"
#include "index/Ref.h"
#include "index/Relation.h"
#include "index/Serialization.h"
#include "index/SymbolCollector.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/ScopeExit.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/Threading.h"

#include <atomic>
#include <chrono>
#include <condition_variable>
#include <memory>
#include <mutex>
#include <numeric>
#include <queue>
#include <random>
#include <string>
#include <thread>

namespace clang {
namespace clangd {

bool BackgroundIndexRebuilder::enoughTUsToRebuild() const {
  if (!ActiveVersion)                         // never built
    return IndexedTUs == TUsBeforeFirstBuild; // use low threshold
  // rebuild if we've reached the (higher) threshold
  return IndexedTUs >= IndexedTUsAtLastRebuild + TUsBeforeRebuild;
}

void BackgroundIndexRebuilder::indexedTU() {
  maybeRebuild("after indexing enough files", [this] {
    ++IndexedTUs;
    if (Loading)
      return false;                      // rebuild once loading finishes
    if (ActiveVersion != StartedVersion) // currently building
      return false;                      // no urgency, avoid overlapping builds
    return enoughTUsToRebuild();
  });
}

void BackgroundIndexRebuilder::idle() {
  maybeRebuild("when background indexer is idle", [this] {
    // rebuild if there's anything new in the index.
    // (even if currently rebuilding! this ensures eventual completeness)
    return IndexedTUs > IndexedTUsAtLastRebuild;
  });
}

void BackgroundIndexRebuilder::startLoading() {
  std::lock_guard<std::mutex> Lock(Mu);
  if (!Loading)
    LoadedShards = 0;
  ++Loading;
}
void BackgroundIndexRebuilder::loadedShard(size_t ShardCount) {
  std::lock_guard<std::mutex> Lock(Mu);
  assert(Loading);
  LoadedShards += ShardCount;
}
void BackgroundIndexRebuilder::doneLoading() {
  maybeRebuild("after loading index from disk", [this] {
    assert(Loading);
    --Loading;
    if (Loading)    // was loading multiple batches concurrently
      return false; // rebuild once the last batch is done.
    // Rebuild if we loaded any shards, or if we stopped an indexedTU rebuild.
    return LoadedShards > 0 || enoughTUsToRebuild();
  });
}

void BackgroundIndexRebuilder::shutdown() {
  std::lock_guard<std::mutex> Lock(Mu);
  ShouldStop = true;
}

void BackgroundIndexRebuilder::maybeRebuild(const char *Reason,
                                            std::function<bool()> Check) {
  unsigned BuildVersion = 0;
  {
    std::lock_guard<std::mutex> Lock(Mu);
    if (!ShouldStop && Check()) {
      BuildVersion = ++StartedVersion;
      IndexedTUsAtLastRebuild = IndexedTUs;
    }
  }
  if (BuildVersion) {
    std::unique_ptr<SymbolIndex> NewIndex;
    {
      vlog("BackgroundIndex: building version {0} {1}", BuildVersion, Reason);
      trace::Span Tracer("RebuildBackgroundIndex");
      SPAN_ATTACH(Tracer, "reason", Reason);
      NewIndex = Source->buildIndex(IndexType::Heavy, DuplicateHandling::Merge);
    }
    {
      std::lock_guard<std::mutex> Lock(Mu);
      // Guard against rebuild finishing in the wrong order.
      if (BuildVersion > ActiveVersion) {
        ActiveVersion = BuildVersion;
        vlog("BackgroundIndex: serving version {0} ({1} bytes)", BuildVersion,
             NewIndex->estimateMemoryUsage());
        Target->reset(std::move(NewIndex));
      }
    }
  }
}

} // namespace clangd
} // namespace clang