@@ -118,8 +118,8 @@ DependencyScanningFilesystemSharedCache::CacheShard::findEntryByFilename(
118118 StringRef Filename) const {
119119 assert (llvm::sys::path::is_absolute_gnu (Filename));
120120 std::lock_guard<std::mutex> LockGuard (CacheLock);
121- auto It = EntriesByFilename .find (Filename);
122- return It == EntriesByFilename .end () ? nullptr : It->getValue ();
121+ auto It = CacheByFilename .find (Filename);
122+ return It == CacheByFilename .end () ? nullptr : It->getValue (). first ;
123123}
124124
125125const CachedFileSystemEntry *
@@ -135,11 +135,16 @@ DependencyScanningFilesystemSharedCache::CacheShard::
135135 getOrEmplaceEntryForFilename (StringRef Filename,
136136 llvm::ErrorOr<llvm::vfs::Status> Stat) {
137137 std::lock_guard<std::mutex> LockGuard (CacheLock);
138- auto Insertion = EntriesByFilename.insert ({Filename, nullptr });
139- if (Insertion.second )
140- Insertion.first ->second =
138+ auto [It, Inserted] = CacheByFilename.insert ({Filename, {nullptr , nullptr }});
139+ auto &[CachedEntry, CachedRealPath] = It->getValue ();
140+ if (!CachedEntry) {
141+ // The entry is not present in the shared cache. Either the cache doesn't
142+ // know about the file at all, or it only knows about its real path.
143+ assert ((Inserted || CachedRealPath) && " existing file with empty pair" );
144+ CachedEntry =
141145 new (EntryStorage.Allocate ()) CachedFileSystemEntry (std::move (Stat));
142- return *Insertion.first ->second ;
146+ }
147+ return *CachedEntry;
143148}
144149
145150const CachedFileSystemEntry &
@@ -148,24 +153,58 @@ DependencyScanningFilesystemSharedCache::CacheShard::getOrEmplaceEntryForUID(
148153 std::unique_ptr<llvm::MemoryBuffer> Contents,
149154 std::optional<cas::ObjectRef> CASContents) {
150155 std::lock_guard<std::mutex> LockGuard (CacheLock);
151- auto Insertion = EntriesByUID.insert ({UID, nullptr });
152- if (Insertion.second ) {
156+ auto [It, Inserted] = EntriesByUID.insert ({UID, nullptr });
157+ auto &CachedEntry = It->getSecond ();
158+ if (Inserted) {
153159 CachedFileContents *StoredContents = nullptr ;
154160 if (Contents)
155161 StoredContents = new (ContentsStorage.Allocate ())
156162 CachedFileContents (std::move (Contents), std::move (CASContents));
157- Insertion. first -> second = new (EntryStorage.Allocate ())
163+ CachedEntry = new (EntryStorage.Allocate ())
158164 CachedFileSystemEntry (std::move (Stat), StoredContents);
159165 }
160- return *Insertion. first -> second ;
166+ return *CachedEntry ;
161167}
162168
163169const CachedFileSystemEntry &
164170DependencyScanningFilesystemSharedCache::CacheShard::
165171 getOrInsertEntryForFilename (StringRef Filename,
166172 const CachedFileSystemEntry &Entry) {
167173 std::lock_guard<std::mutex> LockGuard (CacheLock);
168- return *EntriesByFilename.insert ({Filename, &Entry}).first ->getValue ();
174+ auto [It, Inserted] = CacheByFilename.insert ({Filename, {&Entry, nullptr }});
175+ auto &[CachedEntry, CachedRealPath] = It->getValue ();
176+ if (!Inserted || !CachedEntry)
177+ CachedEntry = &Entry;
178+ return *CachedEntry;
179+ }
180+
181+ const CachedRealPath *
182+ DependencyScanningFilesystemSharedCache::CacheShard::findRealPathByFilename (
183+ StringRef Filename) const {
184+ assert (llvm::sys::path::is_absolute_gnu (Filename));
185+ std::lock_guard<std::mutex> LockGuard (CacheLock);
186+ auto It = CacheByFilename.find (Filename);
187+ return It == CacheByFilename.end () ? nullptr : It->getValue ().second ;
188+ }
189+
190+ const CachedRealPath &DependencyScanningFilesystemSharedCache::CacheShard::
191+ getOrEmplaceRealPathForFilename (StringRef Filename,
192+ llvm::ErrorOr<llvm::StringRef> RealPath) {
193+ std::lock_guard<std::mutex> LockGuard (CacheLock);
194+
195+ const CachedRealPath *&StoredRealPath = CacheByFilename[Filename].second ;
196+ if (!StoredRealPath) {
197+ auto OwnedRealPath = [&]() -> CachedRealPath {
198+ if (!RealPath)
199+ return RealPath.getError ();
200+ return RealPath->str ();
201+ }();
202+
203+ StoredRealPath = new (RealPathStorage.Allocate ())
204+ CachedRealPath (std::move (OwnedRealPath));
205+ }
206+
207+ return *StoredRealPath;
169208}
170209
171210static bool shouldCacheStatFailures (StringRef Filename) {
@@ -239,24 +278,15 @@ DependencyScanningWorkerFilesystem::computeAndStoreResult(
239278llvm::ErrorOr<EntryRef>
240279DependencyScanningWorkerFilesystem::getOrCreateFileSystemEntry (
241280 StringRef OriginalFilename) {
242- StringRef FilenameForLookup;
243281 SmallString<256 > PathBuf;
244- if (llvm::sys::path::is_absolute_gnu (OriginalFilename)) {
245- FilenameForLookup = OriginalFilename;
246- } else if (!WorkingDirForCacheLookup) {
247- return WorkingDirForCacheLookup.getError ();
248- } else {
249- StringRef RelFilename = OriginalFilename;
250- RelFilename.consume_front (" ./" );
251- PathBuf = *WorkingDirForCacheLookup;
252- llvm::sys::path::append (PathBuf, RelFilename);
253- FilenameForLookup = PathBuf.str ();
254- }
255- assert (llvm::sys::path::is_absolute_gnu (FilenameForLookup));
282+ auto FilenameForLookup = tryGetFilenameForLookup (OriginalFilename, PathBuf);
283+ if (!FilenameForLookup)
284+ return FilenameForLookup.getError ();
285+
256286 if (const auto *Entry =
257- findEntryByFilenameWithWriteThrough (FilenameForLookup))
287+ findEntryByFilenameWithWriteThrough (* FilenameForLookup))
258288 return EntryRef (OriginalFilename, *Entry).unwrapError ();
259- auto MaybeEntry = computeAndStoreResult (OriginalFilename, FilenameForLookup);
289+ auto MaybeEntry = computeAndStoreResult (OriginalFilename, * FilenameForLookup);
260290 if (!MaybeEntry)
261291 return MaybeEntry.getError ();
262292 return EntryRef (OriginalFilename, *MaybeEntry).unwrapError ();
@@ -276,6 +306,17 @@ DependencyScanningWorkerFilesystem::status(const Twine &Path) {
276306 return Result->getStatus ();
277307}
278308
309+ bool DependencyScanningWorkerFilesystem::exists (const Twine &Path) {
310+ // While some VFS overlay filesystems may implement more-efficient
311+ // mechanisms for `exists` queries, `DependencyScanningWorkerFilesystem`
312+ // typically wraps `RealFileSystem` which does not specialize `exists`,
313+ // so it is not likely to benefit from such optimizations. Instead,
314+ // it is more-valuable to have this query go through the
315+ // cached-`status` code-path of the `DependencyScanningWorkerFilesystem`.
316+ llvm::ErrorOr<llvm::vfs::Status> Status = status (Path);
317+ return Status && Status->exists ();
318+ }
319+
279320namespace {
280321
281322// / The VFS that is used by clang consumes the \c CachedFileSystemEntry using
@@ -343,6 +384,54 @@ DependencyScanningWorkerFilesystem::openFileForRead(const Twine &Path) {
343384 return DepScanFile::create (Result.get ());
344385}
345386
387+ std::error_code
388+ DependencyScanningWorkerFilesystem::getRealPath (const Twine &Path,
389+ SmallVectorImpl<char > &Output) {
390+ SmallString<256 > OwnedFilename;
391+ StringRef OriginalFilename = Path.toStringRef (OwnedFilename);
392+
393+ SmallString<256 > PathBuf;
394+ auto FilenameForLookup = tryGetFilenameForLookup (OriginalFilename, PathBuf);
395+ if (!FilenameForLookup)
396+ return FilenameForLookup.getError ();
397+
398+ auto HandleCachedRealPath =
399+ [&Output](const CachedRealPath &RealPath) -> std::error_code {
400+ if (!RealPath)
401+ return RealPath.getError ();
402+ Output.assign (RealPath->begin (), RealPath->end ());
403+ return {};
404+ };
405+
406+ // If we already have the result in local cache, no work required.
407+ if (const auto *RealPath =
408+ LocalCache.findRealPathByFilename (*FilenameForLookup))
409+ return HandleCachedRealPath (*RealPath);
410+
411+ // If we have the result in the shared cache, cache it locally.
412+ auto &Shard = SharedCache.getShardForFilename (*FilenameForLookup);
413+ if (const auto *ShardRealPath =
414+ Shard.findRealPathByFilename (*FilenameForLookup)) {
415+ const auto &RealPath = LocalCache.insertRealPathForFilename (
416+ *FilenameForLookup, *ShardRealPath);
417+ return HandleCachedRealPath (RealPath);
418+ }
419+
420+ // If we don't know the real path, compute it...
421+ std::error_code EC = getUnderlyingFS ().getRealPath (OriginalFilename, Output);
422+ llvm::ErrorOr<llvm::StringRef> ComputedRealPath = EC;
423+ if (!EC)
424+ ComputedRealPath = StringRef{Output.data (), Output.size ()};
425+
426+ // ...and try to write it into the shared cache. In case some other thread won
427+ // this race and already wrote its own result there, just adopt it. Write
428+ // whatever is in the shared cache into the local one.
429+ const auto &RealPath = Shard.getOrEmplaceRealPathForFilename (
430+ *FilenameForLookup, ComputedRealPath);
431+ return HandleCachedRealPath (
432+ LocalCache.insertRealPathForFilename (*FilenameForLookup, RealPath));
433+ }
434+
346435std::error_code DependencyScanningWorkerFilesystem::setCurrentWorkingDirectory (
347436 const Twine &Path) {
348437 std::error_code EC = ProxyFileSystem::setCurrentWorkingDirectory (Path);
@@ -364,4 +453,24 @@ void DependencyScanningWorkerFilesystem::updateWorkingDirForCacheLookup() {
364453 llvm::sys::path::is_absolute_gnu (*WorkingDirForCacheLookup));
365454}
366455
456+ llvm::ErrorOr<StringRef>
457+ DependencyScanningWorkerFilesystem::tryGetFilenameForLookup (
458+ StringRef OriginalFilename, llvm::SmallVectorImpl<char > &PathBuf) const {
459+ StringRef FilenameForLookup;
460+ if (llvm::sys::path::is_absolute_gnu (OriginalFilename)) {
461+ FilenameForLookup = OriginalFilename;
462+ } else if (!WorkingDirForCacheLookup) {
463+ return WorkingDirForCacheLookup.getError ();
464+ } else {
465+ StringRef RelFilename = OriginalFilename;
466+ RelFilename.consume_front (" ./" );
467+ PathBuf.assign (WorkingDirForCacheLookup->begin (),
468+ WorkingDirForCacheLookup->end ());
469+ llvm::sys::path::append (PathBuf, RelFilename);
470+ FilenameForLookup = StringRef{PathBuf.begin (), PathBuf.size ()};
471+ }
472+ assert (llvm::sys::path::is_absolute_gnu (FilenameForLookup));
473+ return FilenameForLookup;
474+ }
475+
367476const char DependencyScanningWorkerFilesystem::ID = 0 ;
0 commit comments