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/MemoryBuffer.h" 22 #include "llvm/Support/Path.h" 29 std::string getShardPathFromFilePath(llvm::StringRef ShardRoot,
30 llvm::StringRef FilePath) {
31 llvm::SmallString<128> ShardRootSS(ShardRoot);
32 llvm::sys::path::append(ShardRootSS, llvm::sys::path::filename(FilePath) +
33 "." + llvm::toHex(
digest(FilePath)) +
35 return ShardRootSS.str();
39 writeAtomically(llvm::StringRef OutPath,
40 llvm::function_ref<
void(llvm::raw_ostream &)> Writer) {
42 llvm::SmallString<128> TempPath;
45 llvm::sys::fs::createUniqueFile(OutPath +
".tmp.%%%%%%%%", FD, TempPath);
47 return llvm::errorCodeToError(EC);
50 llvm::make_scope_exit([TempPath] { llvm::sys::fs::remove(TempPath); });
51 llvm::raw_fd_ostream OS(FD,
true);
55 return llvm::errorCodeToError(OS.error());
57 EC = llvm::sys::fs::rename(TempPath, OutPath);
59 return llvm::errorCodeToError(EC);
62 RemoveOnFail.release();
63 return llvm::ErrorSuccess();
68 class DiskBackedIndexStorage :
public BackgroundIndexStorage {
69 std::string DiskShardRoot;
74 DiskBackedIndexStorage(llvm::StringRef
Directory) {
75 llvm::SmallString<128> CDBDirectory(Directory);
76 llvm::sys::path::append(CDBDirectory,
".clangd",
"index");
77 DiskShardRoot = CDBDirectory.str();
79 std::error_code EC = llvm::sys::fs::create_directories(DiskShardRoot);
81 elog(
"Failed to create directory {0} for index storage: {1}",
82 DiskShardRoot, EC.message());
86 std::unique_ptr<IndexFileIn>
87 loadShard(llvm::StringRef ShardIdentifier)
const override {
88 const std::string ShardPath =
89 getShardPathFromFilePath(DiskShardRoot, ShardIdentifier);
90 auto Buffer = llvm::MemoryBuffer::getFile(ShardPath);
94 return llvm::make_unique<IndexFileIn>(std::move(*I));
96 elog(
"Error while reading shard {0}: {1}", ShardIdentifier,
101 llvm::Error storeShard(llvm::StringRef ShardIdentifier,
102 IndexFileOut Shard)
const override {
103 return writeAtomically(
104 getShardPathFromFilePath(DiskShardRoot, ShardIdentifier),
105 [&Shard](llvm::raw_ostream &OS) { OS << Shard; });
111 class NullStorage :
public BackgroundIndexStorage {
113 std::unique_ptr<IndexFileIn>
114 loadShard(llvm::StringRef ShardIdentifier)
const override {
118 llvm::Error storeShard(llvm::StringRef ShardIdentifier,
119 IndexFileOut Shard)
const override {
120 vlog(
"Couldn't find project for {0}, indexing in-memory only",
122 return llvm::Error::success();
127 class DiskBackedIndexStorageManager {
129 DiskBackedIndexStorageManager(
130 std::function<llvm::Optional<ProjectInfo>(
PathRef)> GetProjectInfo)
131 : IndexStorageMapMu(
llvm::make_unique<std::mutex>()),
132 GetProjectInfo(std::move(GetProjectInfo)) {
133 llvm::SmallString<128> HomeDir;
134 llvm::sys::path::home_directory(HomeDir);
135 this->HomeDir = HomeDir.str().str();
140 std::lock_guard<std::mutex> Lock(*IndexStorageMapMu);
141 Path CDBDirectory = HomeDir;
142 if (
auto PI = GetProjectInfo(File))
143 CDBDirectory = PI->SourceRoot;
144 auto &IndexStorage = IndexStorageMap[CDBDirectory];
146 IndexStorage = create(CDBDirectory);
147 return IndexStorage.get();
151 std::unique_ptr<BackgroundIndexStorage> create(
PathRef CDBDirectory) {
152 if (CDBDirectory.empty()) {
153 elog(
"Tried to create storage for empty directory!");
154 return llvm::make_unique<NullStorage>();
156 return llvm::make_unique<DiskBackedIndexStorage>(CDBDirectory);
161 llvm::StringMap<std::unique_ptr<BackgroundIndexStorage>> IndexStorageMap;
162 std::unique_ptr<std::mutex> IndexStorageMapMu;
164 std::function<llvm::Optional<ProjectInfo>(
PathRef)> GetProjectInfo;
171 std::function<llvm::Optional<ProjectInfo>(
PathRef)> GetProjectInfo) {
172 return DiskBackedIndexStorageManager(std::move(GetProjectInfo));
Some operations such as code completion produce a set of candidates.
llvm::unique_function< BackgroundIndexStorage *(PathRef)> Factory
static Factory createDiskBackedStorageFactory(std::function< llvm::Optional< ProjectInfo >(PathRef)> GetProjectInfo)
llvm::StringRef PathRef
A typedef to represent a ref to file path.
llvm::Expected< IndexFileIn > readIndexFile(llvm::StringRef Data)
void vlog(const char *Fmt, Ts &&... Vals)
void elog(const char *Fmt, Ts &&... Vals)
std::string Path
A typedef to represent a file path.
llvm::StringRef Directory
FileDigest digest(llvm::StringRef Content)
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//