================
@@ -151,68 +156,162 @@
DependencyScanningFilesystemSharedCache::getOutOfDateEntries(
return InvalidDiagInfo;
}
-const CachedFileSystemEntry *
-DependencyScanningFilesystemSharedCache::CacheShard::findEntryByFilename(
- StringRef Filename) const {
- assert(llvm::sys::path::is_absolute_gnu(Filename));
- std::lock_guard<std::mutex> LockGuard(CacheLock);
- auto It = CacheByFilename.find(Filename);
- return It == CacheByFilename.end() ? nullptr : It->getValue().first;
-}
-
-const CachedFileSystemEntry *
-DependencyScanningFilesystemSharedCache::CacheShard::findEntryByUID(
- llvm::sys::fs::UniqueID UID) const {
- std::lock_guard<std::mutex> LockGuard(CacheLock);
- auto It = EntriesByUID.find(UID);
- return It == EntriesByUID.end() ? nullptr : It->getSecond();
-}
-
const CachedFileSystemEntry &
DependencyScanningFilesystemSharedCache::CacheShard::
getOrEmplaceEntryForFilename(StringRef Filename,
llvm::ErrorOr<llvm::vfs::Status> Stat) {
std::lock_guard<std::mutex> LockGuard(CacheLock);
- auto [It, Inserted] = CacheByFilename.insert({Filename, {nullptr, nullptr}});
- auto &[CachedEntry, CachedRealPath] = It->getValue();
- if (!CachedEntry) {
- // The entry is not present in the shared cache. Either the cache doesn't
- // know about the file at all, or it only knows about its real path.
- assert((Inserted || CachedRealPath) && "existing file with empty pair");
- CachedEntry =
+ auto [It, Inserted] = CacheByFilename.try_emplace(Filename);
+ auto &State = It->getValue();
+ if (!State.Entry) {
+ // The entry is not present in the shared cache. This method runs only
+ // from inside a producer slot held by the caller, so either the cache
+ // state was just freshly inserted or it already carries an in-flight
+ // slot.
+ assert((Inserted || State.InProgress) &&
+ "cache state should be fresh or carry an in-flight slot held by "
+ "the caller");
+ State.Entry =
new (EntryStorage.Allocate()) CachedFileSystemEntry(std::move(Stat));
}
- return *CachedEntry;
+ return *State.Entry;
+}
+
+DependencyScanningFilesystemSharedCache::SlotAcquisitionResult
+DependencyScanningFilesystemSharedCache::CacheShard::acquireFilenameSlot(
+ StringRef Filename) {
+ assert(llvm::sys::path::is_absolute_gnu(Filename));
+ std::shared_ptr<InProgressEntry> Pending;
+ {
+ std::lock_guard<std::mutex> ShardLock(CacheLock);
+ auto &State = CacheByFilename[Filename];
+
+ // Cache hit.
+ if (State.Entry)
+ return SlotAcquisitionResult{State.Entry, nullptr};
+
+ // No outstanding query: install an in-progress entry and become the
+ // producer.
+ if (!State.InProgress) {
+ State.InProgress = std::make_shared<InProgressEntry>();
+ return SlotAcquisitionResult{std::error_code{}, State.InProgress};
+ }
+
+ // Another worker is producing for this filename. Capture the shared_ptr
+ // by copy so the slot stays alive for us to wait on after we release the
+ // shard lock (the producer resets State.InProgress on publish).
+ Pending = State.InProgress;
+ }
+
+ // Wait for the producer on the slot's own mutex/CV, with the shard lock
+ // released so unrelated keys in this shard are not blocked by our wait, then
+ // adopt its outcome. This holds even for a negative result the producer
+ // chose not to cache: our query overlapped the producer's in time, so we can
+ // share its answer without that constituting caching across separate
queries.
+ std::unique_lock<std::mutex> EntryLock(Pending->Mutex);
+ Pending->CondVar.wait(EntryLock, [&] { return Pending->Done; });
+ return SlotAcquisitionResult{Pending->Result, nullptr};
+}
+
+DependencyScanningFilesystemSharedCache::SlotAcquisitionResult
+DependencyScanningFilesystemSharedCache::CacheShard::acquireUIDSlot(
+ llvm::sys::fs::UniqueID UID) {
+ std::shared_ptr<InProgressEntry> Pending;
+ {
+ std::lock_guard<std::mutex> ShardLock(CacheLock);
+ auto &State = EntriesByUID[UID];
+
+ // Cache hit.
+ if (State.Entry)
+ return SlotAcquisitionResult{State.Entry, nullptr};
+
+ // No outstanding query: install an in-progress entry and become the
+ // producer.
+ if (!State.InProgress) {
+ State.InProgress = std::make_shared<InProgressEntry>();
+ return SlotAcquisitionResult{std::error_code{}, State.InProgress};
+ }
+
+ // Another worker is producing for this UID. Capture the shared_ptr by copy
+ // so the slot stays alive for us to wait on after we release the shard
+ // lock.
+ Pending = State.InProgress;
+ }
+
+ // Wait for the producer on the slot's own mutex/CV, with the shard lock
+ // released. Unlike the filename slot, a UID producer always publishes a
+ // non-null entry, so the adopted result is never an error.
+ std::unique_lock<std::mutex> EntryLock(Pending->Mutex);
+ Pending->CondVar.wait(EntryLock, [&] { return Pending->Done; });
+ assert(Pending->Result && *Pending->Result &&
+ "in-progress UID slot fulfilled without an entry");
+ return SlotAcquisitionResult{Pending->Result, nullptr};
+}
+
+void DependencyScanningFilesystemSharedCache::CacheShard::fulfillFilenameSlot(
+ StringRef Filename,
+ const std::shared_ptr<
+ DependencyScanningFilesystemSharedCache::InProgressEntry> &IPE,
+ llvm::ErrorOr<const CachedFileSystemEntry *> Result) {
+ {
+ std::lock_guard<std::mutex> ShardLock(CacheLock);
+ auto &State = CacheByFilename[Filename];
+ // Only a resolved entry is recorded for later queries; an uncached
+ // negative stat (an error) is shared with current waiters but not
+ // persisted in the shard.
+ if (Result && !State.Entry)
+ State.Entry = *Result;
+ State.InProgress.reset();
+ }
+ // Publish the result under the slot's own mutex, then notify waiters.
Waiters
+ // read Done/Result under this same mutex, so the predicate wait cannot miss
+ // the wakeup. The producer's shared_ptr keeps the slot (and CondVar) alive
+ // across notify_all.
+ {
+ std::lock_guard<std::mutex> EntryLock(IPE->Mutex);
+ IPE->Result = Result;
+ IPE->Done = true;
+ }
+ IPE->CondVar.notify_all();
+}
+
+void DependencyScanningFilesystemSharedCache::CacheShard::fulfillUIDSlot(
+ llvm::sys::fs::UniqueID UID,
+ const std::shared_ptr<
+ DependencyScanningFilesystemSharedCache::InProgressEntry> &IPE,
+ const CachedFileSystemEntry *Result) {
+ {
+ std::lock_guard<std::mutex> ShardLock(CacheLock);
----------------
jansvoboda11 wrote:
(Also fine to do it in a follow-up.)
https://github.com/llvm/llvm-project/pull/199680
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits