@@ -118,8 +118,8 @@ DependencyScanningFilesystemSharedCache::CacheShard::findEntryByFilename(
118
118
StringRef Filename) const {
119
119
assert (llvm::sys::path::is_absolute_gnu (Filename));
120
120
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 ;
123
123
}
124
124
125
125
const CachedFileSystemEntry *
@@ -135,11 +135,16 @@ DependencyScanningFilesystemSharedCache::CacheShard::
135
135
getOrEmplaceEntryForFilename (StringRef Filename,
136
136
llvm::ErrorOr<llvm::vfs::Status> Stat) {
137
137
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 =
141
145
new (EntryStorage.Allocate ()) CachedFileSystemEntry (std::move (Stat));
142
- return *Insertion.first ->second ;
146
+ }
147
+ return *CachedEntry;
143
148
}
144
149
145
150
const CachedFileSystemEntry &
@@ -148,24 +153,58 @@ DependencyScanningFilesystemSharedCache::CacheShard::getOrEmplaceEntryForUID(
148
153
std::unique_ptr<llvm::MemoryBuffer> Contents,
149
154
std::optional<cas::ObjectRef> CASContents) {
150
155
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) {
153
159
CachedFileContents *StoredContents = nullptr ;
154
160
if (Contents)
155
161
StoredContents = new (ContentsStorage.Allocate ())
156
162
CachedFileContents (std::move (Contents), std::move (CASContents));
157
- Insertion. first -> second = new (EntryStorage.Allocate ())
163
+ CachedEntry = new (EntryStorage.Allocate ())
158
164
CachedFileSystemEntry (std::move (Stat), StoredContents);
159
165
}
160
- return *Insertion. first -> second ;
166
+ return *CachedEntry ;
161
167
}
162
168
163
169
const CachedFileSystemEntry &
164
170
DependencyScanningFilesystemSharedCache::CacheShard::
165
171
getOrInsertEntryForFilename (StringRef Filename,
166
172
const CachedFileSystemEntry &Entry) {
167
173
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;
169
208
}
170
209
171
210
static bool shouldCacheStatFailures (StringRef Filename) {
@@ -239,24 +278,15 @@ DependencyScanningWorkerFilesystem::computeAndStoreResult(
239
278
llvm::ErrorOr<EntryRef>
240
279
DependencyScanningWorkerFilesystem::getOrCreateFileSystemEntry (
241
280
StringRef OriginalFilename) {
242
- StringRef FilenameForLookup;
243
281
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
+
256
286
if (const auto *Entry =
257
- findEntryByFilenameWithWriteThrough (FilenameForLookup))
287
+ findEntryByFilenameWithWriteThrough (* FilenameForLookup))
258
288
return EntryRef (OriginalFilename, *Entry).unwrapError ();
259
- auto MaybeEntry = computeAndStoreResult (OriginalFilename, FilenameForLookup);
289
+ auto MaybeEntry = computeAndStoreResult (OriginalFilename, * FilenameForLookup);
260
290
if (!MaybeEntry)
261
291
return MaybeEntry.getError ();
262
292
return EntryRef (OriginalFilename, *MaybeEntry).unwrapError ();
@@ -276,6 +306,17 @@ DependencyScanningWorkerFilesystem::status(const Twine &Path) {
276
306
return Result->getStatus ();
277
307
}
278
308
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
+
279
320
namespace {
280
321
281
322
// / The VFS that is used by clang consumes the \c CachedFileSystemEntry using
@@ -343,6 +384,54 @@ DependencyScanningWorkerFilesystem::openFileForRead(const Twine &Path) {
343
384
return DepScanFile::create (Result.get ());
344
385
}
345
386
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
+
346
435
std::error_code DependencyScanningWorkerFilesystem::setCurrentWorkingDirectory (
347
436
const Twine &Path) {
348
437
std::error_code EC = ProxyFileSystem::setCurrentWorkingDirectory (Path);
@@ -364,4 +453,24 @@ void DependencyScanningWorkerFilesystem::updateWorkingDirForCacheLookup() {
364
453
llvm::sys::path::is_absolute_gnu (*WorkingDirForCacheLookup));
365
454
}
366
455
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
+
367
476
const char DependencyScanningWorkerFilesystem::ID = 0 ;
0 commit comments