clang-tools 22.0.0git
BackgroundIndexStorage.cpp
Go to the documentation of this file.
1//== BackgroundIndexStorage.cpp - Provide caching support to BackgroundIndex ==/
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
10#include "index/Background.h"
11#include "support/Logger.h"
12#include "support/Path.h"
13#include "llvm/ADT/SmallString.h"
14#include "llvm/ADT/StringRef.h"
15#include "llvm/Support/Error.h"
16#include "llvm/Support/FileSystem.h"
17#include "llvm/Support/MemoryBuffer.h"
18#include "llvm/Support/Path.h"
19#include "llvm/Support/raw_ostream.h"
20#include <functional>
21#include <optional>
22
23namespace clang {
24namespace clangd {
25namespace {
26
27std::string getShardPathFromFilePath(llvm::StringRef ShardRoot,
28 llvm::StringRef FilePath) {
29 llvm::SmallString<128> ShardRootSS(ShardRoot);
30 llvm::sys::path::append(ShardRootSS, llvm::sys::path::filename(FilePath) +
31 "." + llvm::toHex(digest(FilePath)) +
32 ".idx");
33 return std::string(ShardRootSS);
34}
35
36// Uses disk as a storage for index shards.
37class DiskBackedIndexStorage : public BackgroundIndexStorage {
38 std::string DiskShardRoot;
39
40public:
41 // Creates `DiskShardRoot` and any parents during construction.
42 DiskBackedIndexStorage(llvm::StringRef Directory) : DiskShardRoot(Directory) {
43 std::error_code OK;
44 std::error_code EC = llvm::sys::fs::create_directories(DiskShardRoot);
45 if (EC != OK) {
46 elog("Failed to create directory {0} for index storage: {1}",
47 DiskShardRoot, EC.message());
48 return;
49 }
50 // Create a .gitignore file in the directory to ignore all files.
51 llvm::SmallString<128> GitignorePath(DiskShardRoot);
52 llvm::sys::path::append(GitignorePath, ".gitignore");
53 auto Error = llvm::writeToOutput(GitignorePath, [](llvm::raw_ostream &OS) {
54 OS << "# This file is autogenerated by clangd.\n*\n";
55 return llvm::Error::success();
56 });
57 llvm::consumeError(std::move(Error));
58 }
59
60 std::unique_ptr<IndexFileIn>
61 loadShard(llvm::StringRef ShardIdentifier) const override {
62 const std::string ShardPath =
63 getShardPathFromFilePath(DiskShardRoot, ShardIdentifier);
64 auto Buffer = llvm::MemoryBuffer::getFile(ShardPath);
65 if (!Buffer)
66 return nullptr;
67 if (auto I =
68 readIndexFile(Buffer->get()->getBuffer(), SymbolOrigin::Background))
69 return std::make_unique<IndexFileIn>(std::move(*I));
70 else
71 elog("Error while reading shard {0}: {1}", ShardIdentifier,
72 I.takeError());
73 return nullptr;
74 }
75
76 llvm::Error storeShard(llvm::StringRef ShardIdentifier,
77 IndexFileOut Shard) const override {
78 auto ShardPath = getShardPathFromFilePath(DiskShardRoot, ShardIdentifier);
79 return llvm::writeToOutput(ShardPath, [&Shard](llvm::raw_ostream &OS) {
80 OS << Shard;
81 return llvm::Error::success();
82 });
83 }
84};
85
86// Doesn't persist index shards anywhere (used when the CDB dir is unknown).
87// We could consider indexing into ~/.clangd/ or so instead.
88class NullStorage : public BackgroundIndexStorage {
89public:
90 std::unique_ptr<IndexFileIn>
91 loadShard(llvm::StringRef ShardIdentifier) const override {
92 return nullptr;
93 }
94
95 llvm::Error storeShard(llvm::StringRef ShardIdentifier,
96 IndexFileOut Shard) const override {
97 vlog("Couldn't find project for {0}, indexing in-memory only",
98 ShardIdentifier);
99 return llvm::Error::success();
100 }
101};
102
103// Creates and owns IndexStorages for multiple CDBs.
104// When a CDB root is found, shards are stored in $ROOT/.cache/clangd/index/.
105// When no root is found, the fallback path is ~/.cache/clangd/index/.
106class DiskBackedIndexStorageManager {
107public:
108 DiskBackedIndexStorageManager(
109 std::function<std::optional<ProjectInfo>(PathRef)> GetProjectInfo)
110 : IndexStorageMapMu(std::make_unique<std::mutex>()),
111 GetProjectInfo(std::move(GetProjectInfo)) {
112 llvm::SmallString<128> FallbackDir;
113 if (llvm::sys::path::cache_directory(FallbackDir))
114 llvm::sys::path::append(FallbackDir, "clangd", "index");
115 this->FallbackDir = FallbackDir.str().str();
116 }
117
118 // Creates or fetches to storage from cache for the specified project.
119 BackgroundIndexStorage *operator()(PathRef File) {
120 std::lock_guard<std::mutex> Lock(*IndexStorageMapMu);
121 llvm::SmallString<128> StorageDir(FallbackDir);
122 if (auto PI = GetProjectInfo(File)) {
123 StorageDir = PI->SourceRoot;
124 llvm::sys::path::append(StorageDir, ".cache", "clangd", "index");
125 }
126 auto &IndexStorage = IndexStorageMap[StorageDir];
127 if (!IndexStorage)
128 IndexStorage = create(StorageDir);
129 return IndexStorage.get();
130 }
131
132private:
133 std::unique_ptr<BackgroundIndexStorage> create(PathRef CDBDirectory) {
134 if (CDBDirectory.empty()) {
135 elog("Tried to create storage for empty directory!");
136 return std::make_unique<NullStorage>();
137 }
138 return std::make_unique<DiskBackedIndexStorage>(CDBDirectory);
139 }
140
141 Path FallbackDir;
142
143 llvm::StringMap<std::unique_ptr<BackgroundIndexStorage>> IndexStorageMap;
144 std::unique_ptr<std::mutex> IndexStorageMapMu;
145
146 std::function<std::optional<ProjectInfo>(PathRef)> GetProjectInfo;
147};
148
149} // namespace
150
153 std::function<std::optional<ProjectInfo>(PathRef)> GetProjectInfo) {
154 return DiskBackedIndexStorageManager(std::move(GetProjectInfo));
155}
156
157} // namespace clangd
158} // namespace clang
static cl::opt< std::string > Directory(cl::Positional, cl::Required, cl::desc("<Search Root Directory>"))
llvm::unique_function< BackgroundIndexStorage *(PathRef)> Factory
Definition Background.h:58
static Factory createDiskBackedStorageFactory(std::function< std::optional< ProjectInfo >(PathRef)> GetProjectInfo)
FIXME: Skip testing on windows temporarily due to the different escaping code mode.
Definition AST.cpp:45
@ Error
An error message.
Definition Protocol.h:734
llvm::Expected< IndexFileIn > readIndexFile(llvm::StringRef Data, SymbolOrigin Origin)
FileDigest digest(llvm::StringRef Content)
void vlog(const char *Fmt, Ts &&... Vals)
Definition Logger.h:72
llvm::StringRef PathRef
A typedef to represent a ref to file path.
Definition Path.h:29
std::string Path
A typedef to represent a file path.
Definition Path.h:26
void elog(const char *Fmt, Ts &&... Vals)
Definition Logger.h:61
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//