clang-tools 10.0.0

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
9 #include "GlobalCompilationDatabase.h"
10 #include "Logger.h"
11 #include "Path.h"
12 #include "index/Background.h"
13 #include "llvm/ADT/Optional.h"
14 #include "llvm/ADT/STLExtras.h"
15 #include "llvm/ADT/ScopeExit.h"
16 #include "llvm/ADT/SmallString.h"
17 #include "llvm/ADT/SmallVector.h"
18 #include "llvm/ADT/StringRef.h"
19 #include "llvm/Support/Error.h"
20 #include "llvm/Support/FileSystem.h"
21 #include "llvm/Support/FileUtilities.h"
22 #include "llvm/Support/MemoryBuffer.h"
23 #include "llvm/Support/Path.h"
24 #include <functional>
25
26 namespace clang {
27 namespace clangd {
28 namespace {
29
30 std::string getShardPathFromFilePath(llvm::StringRef ShardRoot,
31 llvm::StringRef FilePath) {
32 llvm::SmallString<128> ShardRootSS(ShardRoot);
33 llvm::sys::path::append(ShardRootSS, llvm::sys::path::filename(FilePath) +
34 "." + llvm::toHex(digest(FilePath)) +
35 ".idx");
36 return ShardRootSS.str();
37 }
38
39 // Uses disk as a storage for index shards. Creates a directory called
40 // ".clangd/index/" under the path provided during construction.
41 class DiskBackedIndexStorage : public BackgroundIndexStorage {
42 std::string DiskShardRoot;
43
44 public:
45 // Sets DiskShardRoot to (Directory + ".clangd/index/") which is the base
46 // directory for all shard files.
47 DiskBackedIndexStorage(llvm::StringRef Directory) {
48 llvm::SmallString<128> CDBDirectory(Directory);
49 llvm::sys::path::append(CDBDirectory, ".clangd", "index");
50 DiskShardRoot = CDBDirectory.str();
51 std::error_code OK;
52 std::error_code EC = llvm::sys::fs::create_directories(DiskShardRoot);
53 if (EC != OK) {
54 elog("Failed to create directory {0} for index storage: {1}",
55 DiskShardRoot, EC.message());
56 }
57 }
58
59 std::unique_ptr<IndexFileIn>
60 loadShard(llvm::StringRef ShardIdentifier) const override {
61 const std::string ShardPath =
62 getShardPathFromFilePath(DiskShardRoot, ShardIdentifier);
63 auto Buffer = llvm::MemoryBuffer::getFile(ShardPath);
64 if (!Buffer)
65 return nullptr;
66 if (auto I = readIndexFile(Buffer->get()->getBuffer()))
67 return std::make_unique<IndexFileIn>(std::move(*I));
68 else
69 elog("Error while reading shard {0}: {1}", ShardIdentifier,
70 I.takeError());
71 return nullptr;
72 }
73
74 llvm::Error storeShard(llvm::StringRef ShardIdentifier,
75 IndexFileOut Shard) const override {
76 auto ShardPath = getShardPathFromFilePath(DiskShardRoot, ShardIdentifier);
77 return llvm::writeFileAtomically(ShardPath + ".tmp.%%%%%%%%", ShardPath,
78 [&Shard](llvm::raw_ostream &OS) {
79 OS << Shard;
80 return llvm::Error::success();
81 });
82 }
83 };
84
85 // Doesn't persist index shards anywhere (used when the CDB dir is unknown).
86 // We could consider indexing into ~/.clangd/ or so instead.
87 class NullStorage : public BackgroundIndexStorage {
88 public:
89 std::unique_ptr<IndexFileIn>
90 loadShard(llvm::StringRef ShardIdentifier) const override {
91 return nullptr;
92 }
93
94 llvm::Error storeShard(llvm::StringRef ShardIdentifier,
95 IndexFileOut Shard) const override {
96 vlog("Couldn't find project for {0}, indexing in-memory only",
97 ShardIdentifier);
98 return llvm::Error::success();
99 }
100 };
101
102 // Creates and owns IndexStorages for multiple CDBs.
103 class DiskBackedIndexStorageManager {
104 public:
105 DiskBackedIndexStorageManager(
106 std::function<llvm::Optional<ProjectInfo>(PathRef)> GetProjectInfo)
107 : IndexStorageMapMu(std::make_unique<std::mutex>()),
108 GetProjectInfo(std::move(GetProjectInfo)) {
109 llvm::SmallString<128> HomeDir;
110 llvm::sys::path::home_directory(HomeDir);
111 this->HomeDir = HomeDir.str().str();
112 }
113
114 // Creates or fetches to storage from cache for the specified project.
115 BackgroundIndexStorage *operator()(PathRef File) {
116 std::lock_guard<std::mutex> Lock(*IndexStorageMapMu);
117 Path CDBDirectory = HomeDir;
118 if (auto PI = GetProjectInfo(File))
119 CDBDirectory = PI->SourceRoot;
120 auto &IndexStorage = IndexStorageMap[CDBDirectory];
121 if (!IndexStorage)
122 IndexStorage = create(CDBDirectory);
123 return IndexStorage.get();
124 }
125
126 private:
127 std::unique_ptr<BackgroundIndexStorage> create(PathRef CDBDirectory) {
128 if (CDBDirectory.empty()) {
129 elog("Tried to create storage for empty directory!");
130 return std::make_unique<NullStorage>();
131 }
132 return std::make_unique<DiskBackedIndexStorage>(CDBDirectory);
133 }
134
135 Path HomeDir;
136
137 llvm::StringMap<std::unique_ptr<BackgroundIndexStorage>> IndexStorageMap;
138 std::unique_ptr<std::mutex> IndexStorageMapMu;
139
140 std::function<llvm::Optional<ProjectInfo>(PathRef)> GetProjectInfo;
141 };
142
143 } // namespace
144
145 BackgroundIndexStorage::Factory
146 BackgroundIndexStorage::createDiskBackedStorageFactory(
147 std::function<llvm::Optional<ProjectInfo>(PathRef)> GetProjectInfo) {
148 return DiskBackedIndexStorageManager(std::move(GetProjectInfo));
149 }
150
151 } // namespace clangd
152 } // namespace clang
clang::clangd::BackgroundIndexStorage::Factory
llvm::unique_function< BackgroundIndexStorage *(PathRef)> Factory
Definition: Background.h:56
clang::clangd::MessageType::Error
An error message.
clang::clangd::BackgroundIndexStorage::createDiskBackedStorageFactory
static Factory createDiskBackedStorageFactory(std::function< llvm::Optional< ProjectInfo >(PathRef)> GetProjectInfo)
Definition: BackgroundIndexStorage.cpp:146
clang::clangd::PathRef
llvm::StringRef PathRef
A typedef to represent a ref to file path.
Definition: Path.h:23
clang::clangd::readIndexFile
llvm::Expected< IndexFileIn > readIndexFile(llvm::StringRef Data)
Definition: Serialization.cpp:652
clang::clangd::vlog
void vlog(const char *Fmt, Ts &&... Vals)
Definition: Logger.h:67
clang::clangd::elog
void elog(const char *Fmt, Ts &&... Vals)
Definition: Logger.h:56
GlobalCompilationDatabase.h
clang::clangd::Path
std::string Path
A typedef to represent a file path.
Definition: Path.h:20
Directory
llvm::StringRef Directory
Definition: Serialization.cpp:387
clang::clangd::digest
FileDigest digest(llvm::StringRef Content)
Definition: SourceCode.cpp:675
Logger.h
Background.h
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ApplyReplacements.h:27
Path.h
clang::clangd::CompletionItemKind::File