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"
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)) +
36 return std::string(ShardRootSS.str());
40 class DiskBackedIndexStorage :
public BackgroundIndexStorage {
41 std::string DiskShardRoot;
47 std::error_code EC = llvm::sys::fs::create_directories(DiskShardRoot);
49 elog(
"Failed to create directory {0} for index storage: {1}",
50 DiskShardRoot, EC.message());
54 std::unique_ptr<IndexFileIn>
55 loadShard(llvm::StringRef ShardIdentifier)
const override {
56 const std::string ShardPath =
57 getShardPathFromFilePath(DiskShardRoot, ShardIdentifier);
58 auto Buffer = llvm::MemoryBuffer::getFile(ShardPath);
62 return std::make_unique<IndexFileIn>(std::move(*I));
64 elog(
"Error while reading shard {0}: {1}", ShardIdentifier,
69 llvm::Error storeShard(llvm::StringRef ShardIdentifier,
70 IndexFileOut Shard)
const override {
71 auto ShardPath = getShardPathFromFilePath(DiskShardRoot, ShardIdentifier);
72 return llvm::writeFileAtomically(ShardPath +
".tmp.%%%%%%%%", ShardPath,
73 [&Shard](llvm::raw_ostream &
OS) {
75 return llvm::Error::success();
82 class NullStorage :
public BackgroundIndexStorage {
84 std::unique_ptr<IndexFileIn>
85 loadShard(llvm::StringRef ShardIdentifier)
const override {
89 llvm::Error storeShard(llvm::StringRef ShardIdentifier,
90 IndexFileOut Shard)
const override {
91 vlog(
"Couldn't find project for {0}, indexing in-memory only",
93 return llvm::Error::success();
100 class DiskBackedIndexStorageManager {
102 DiskBackedIndexStorageManager(
103 std::function<llvm::Optional<ProjectInfo>(
PathRef)> GetProjectInfo)
104 : IndexStorageMapMu(std::make_unique<std::mutex>()),
105 GetProjectInfo(std::move(GetProjectInfo)) {
106 llvm::SmallString<128> FallbackDir;
107 if (llvm::sys::path::cache_directory(FallbackDir))
108 llvm::sys::path::append(FallbackDir,
"clangd",
"index");
109 this->FallbackDir = FallbackDir.str().str();
114 std::lock_guard<std::mutex> Lock(*IndexStorageMapMu);
115 llvm::SmallString<128> StorageDir(FallbackDir);
116 if (
auto PI = GetProjectInfo(
File)) {
117 StorageDir = PI->SourceRoot;
118 llvm::sys::path::append(StorageDir,
".cache",
"clangd",
"index");
120 auto &IndexStorage = IndexStorageMap[StorageDir];
122 IndexStorage = create(StorageDir);
123 return IndexStorage.get();
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>();
132 return std::make_unique<DiskBackedIndexStorage>(CDBDirectory);
137 llvm::StringMap<std::unique_ptr<BackgroundIndexStorage>> IndexStorageMap;
138 std::unique_ptr<std::mutex> IndexStorageMapMu;
140 std::function<llvm::Optional<ProjectInfo>(
PathRef)> GetProjectInfo;
147 std::function<llvm::Optional<ProjectInfo>(
PathRef)> GetProjectInfo) {
148 return DiskBackedIndexStorageManager(std::move(GetProjectInfo));