https://github.com/artemcm updated 
https://github.com/llvm/llvm-project/pull/199680

>From 8bc818af5d4d347d36d3e65d2925f6b0e0870cce Mon Sep 17 00:00:00 2001
From: Artem Chikin <[email protected]>
Date: Tue, 26 May 2026 13:06:48 +0100
Subject: [PATCH] [clang][deps] Add in-flight query caching to
 `DependencyScanningFilesystemSharedCache`

Concurrent dep-scan workers querying the same filename or UID each issue their 
own `stat` and `open` against the underlying filesystem; only the first to 
finish wins the cache insert, the others' work is wasted.

Add per-key in-flight tracking to `CacheShard`. `InProgressByFilename` and 
`InProgressByUID` map each active key to a
`std::shared_ptr<InProgressEntry>` carrying a `std::condition_variable`, a 
`Done` predicate, and the produced entry pointer. `acquireFilenameSlot` / 
`acquireUIDSlot` collapse three outcomes (resolved hit, in-progress wait, fresh 
producer slot) into one critical section against the shard lock. 
`fulfilFilenameSlot`,`fulfilUIDSlot` publish the produced entry, set `Done`, 
erase the slot, and `notify_all` waiters outside the lock.

`computeAndStoreResult` now claims the filename slot before `stat` and the UID 
slot before `readFile`, so both stat and open redundancy
collapse.
---
 .../DependencyScanningFilesystem.h            |  81 ++++++--
 .../DependencyScanningFilesystem.cpp          | 192 ++++++++++++++---
 .../DependencyScanningFilesystemTest.cpp      | 194 ++++++++++++++++++
 3 files changed, 417 insertions(+), 50 deletions(-)

diff --git 
a/clang/include/clang/DependencyScanning/DependencyScanningFilesystem.h 
b/clang/include/clang/DependencyScanning/DependencyScanningFilesystem.h
index f50332c964ced..81f76e3250362 100644
--- a/clang/include/clang/DependencyScanning/DependencyScanningFilesystem.h
+++ b/clang/include/clang/DependencyScanning/DependencyScanningFilesystem.h
@@ -16,6 +16,8 @@
 #include "llvm/Support/Allocator.h"
 #include "llvm/Support/ErrorOr.h"
 #include "llvm/Support/VirtualFileSystem.h"
+#include <condition_variable>
+#include <memory>
 #include <mutex>
 #include <optional>
 #include <variant>
@@ -152,6 +154,28 @@ using CachedRealPath = llvm::ErrorOr<std::string>;
 /// the worker threads.
 class DependencyScanningFilesystemSharedCache {
 public:
+  /// Tracks a cache entry whose value is currently being computed by one
+  /// worker so that other workers arriving at the same key can wait for the
+  /// result rather than producing it in parallel. The producer publishes the
+  /// resolved entry into \c Result, sets \c Done, and notifies waiters via
+  /// \c CondVar. Waiters synchronize through the owning shard's \c CacheLock.
+  struct InProgressEntry {
+    std::condition_variable CondVar;
+    bool Done = false;
+    const CachedFileSystemEntry *Result = nullptr;
+  };
+
+  /// Outcome of attempting to claim a slot for a given key. Exactly one of
+  /// \c Resolved or \c Produce is non-null:
+  ///   - \c Resolved: the cache (or another worker) has already produced the
+  ///     entry; the caller should use it.
+  ///   - \c Produce: the caller has the right to produce the entry and
+  ///     must call the matching \c fulfil*Slot once finished.
+  struct SlotAcquisitionResult {
+    const CachedFileSystemEntry *Resolved;
+    std::shared_ptr<InProgressEntry> Produce;
+  };
+
   struct CacheShard {
     /// The mutex that needs to be locked before mutation of any member.
     mutable std::mutex CacheLock;
@@ -166,6 +190,18 @@ class DependencyScanningFilesystemSharedCache {
     llvm::DenseMap<llvm::sys::fs::UniqueID, const CachedFileSystemEntry *>
         EntriesByUID;
 
+    /// Filenames whose cache entry is currently being computed. A second
+    /// worker reaching the same filename will wait on the entry's condition
+    /// variable rather than racing the underlying filesystem.
+    llvm::StringMap<std::shared_ptr<InProgressEntry>> InProgressByFilename;
+
+    /// Unique IDs whose cache entry is currently being computed. A worker
+    /// that has stat()-ed a file and gotten a UID already in flight (perhaps
+    /// reached under a different filename) will wait here instead of opening
+    /// the file a second time.
+    llvm::DenseMap<llvm::sys::fs::UniqueID, std::shared_ptr<InProgressEntry>>
+        InProgressByUID;
+
     /// The backing storage for cached entries.
     llvm::SpecificBumpPtrAllocator<CachedFileSystemEntry> EntryStorage;
 
@@ -202,6 +238,35 @@ class DependencyScanningFilesystemSharedCache {
     getOrInsertEntryForFilename(StringRef Filename,
                                 const CachedFileSystemEntry &Entry);
 
+    /// Claims a slot for \p Filename. If a resolved entry already exists,
+    /// returns it. If another worker is currently producing a result for this
+    /// filename, blocks on its \c InProgressEntry until done and returns the
+    /// produced entry. Otherwise installs a fresh \c InProgressEntry and
+    /// returns it as a producer slot which the caller must complete via
+    /// \c fulfilFilenameSlot.
+    SlotAcquisitionResult acquireFilenameSlot(StringRef);
+
+    /// Claims a slot for \p UID. Same semantics as \c acquireFilenameSlot but
+    /// keyed by unique ID; used after \c stat() has identified a file so that
+    /// concurrent \c readFile() calls for the same on-disk file (reached via
+    /// different filenames) collapse onto a single open.
+    SlotAcquisitionResult acquireUIDSlot(llvm::sys::fs::UniqueID);
+
+    /// Completes a producer slot acquired via \c acquireFilenameSlot.
+    /// Publishes \p Result under \p Filename in \c CacheByFilename,
+    /// records it in the slot, marks the slot done, removes the
+    /// in-progress entry, and notifies waiters.
+    void fulfilFilenameSlot(StringRef, const std::shared_ptr<InProgressEntry> 
&,
+                            const CachedFileSystemEntry *);
+
+    /// Completes a producer slot acquired via \c acquireUIDSlot.
+    /// Publishes \p Result under \p UID in \c EntriesByUID, records
+    /// it in the slot, marks the slot done, removes the in-progress
+    /// entry, and notifies waiters.
+    void fulfilUIDSlot(llvm::sys::fs::UniqueID,
+                       const std::shared_ptr<InProgressEntry> &,
+                       const CachedFileSystemEntry *);
+
     /// Returns the real path associated with the filename or nullptr if none 
is
     /// found.
     const CachedRealPath *findRealPathByFilename(StringRef Filename) const;
@@ -439,22 +504,6 @@ class DependencyScanningWorkerFilesystem
   const CachedFileSystemEntry &
   getOrEmplaceSharedEntryForUID(TentativeEntry TEntry);
 
-  /// Returns entry associated with the filename or nullptr if none is found.
-  ///
-  /// Returns entry from local cache if there is some. Otherwise, if the entry
-  /// is found in the shared cache, writes it through the local cache and
-  /// returns it. Otherwise returns nullptr.
-  const CachedFileSystemEntry *
-  findEntryByFilenameWithWriteThrough(StringRef Filename);
-
-  /// Returns entry associated with the unique ID in the shared cache or 
nullptr
-  /// if none is found.
-  const CachedFileSystemEntry *
-  findSharedEntryByUID(llvm::vfs::Status Stat) const {
-    return SharedCache.getShardForUID(Stat.getUniqueID())
-        .findEntryByUID(Stat.getUniqueID());
-  }
-
   /// Associates the given entry with the filename in the local cache and
   /// returns it.
   const CachedFileSystemEntry &
diff --git a/clang/lib/DependencyScanning/DependencyScanningFilesystem.cpp 
b/clang/lib/DependencyScanning/DependencyScanningFilesystem.cpp
index 49dad3758cf57..915b28dd64c07 100644
--- a/clang/lib/DependencyScanning/DependencyScanningFilesystem.cpp
+++ b/clang/lib/DependencyScanning/DependencyScanningFilesystem.cpp
@@ -184,6 +184,101 @@ DependencyScanningFilesystemSharedCache::CacheShard::
   return *CachedEntry;
 }
 
+DependencyScanningFilesystemSharedCache::SlotAcquisitionResult
+DependencyScanningFilesystemSharedCache::CacheShard::acquireFilenameSlot(
+    StringRef Filename) {
+  assert(llvm::sys::path::is_absolute_gnu(Filename));
+  std::unique_lock<std::mutex> LockGuard(CacheLock);
+  // Cache hit.
+  if (auto It = CacheByFilename.find(Filename); It != CacheByFilename.end()) {
+    if (const auto *Entry = It->getValue().first)
+      return SlotAcquisitionResult{Entry, nullptr};
+  }
+
+  // Another worker is producing for this filename, wait for it.
+  if (auto It = InProgressByFilename.find(Filename);
+      It != InProgressByFilename.end()) {
+    std::shared_ptr<InProgressEntry> Pending = It->second;
+    Pending->CondVar.wait(LockGuard, [&] { return Pending->Done; });
+    assert(Pending->Result &&
+           "in-progress filename slot fulfilled without an entry");
+    return SlotAcquisitionResult{Pending->Result, nullptr};
+  }
+
+  // Install an in-progress entry and return it.
+  auto Pending = std::make_shared<InProgressEntry>();
+  InProgressByFilename.try_emplace(Filename, Pending);
+  return SlotAcquisitionResult{nullptr, std::move(Pending)};
+}
+
+DependencyScanningFilesystemSharedCache::SlotAcquisitionResult
+DependencyScanningFilesystemSharedCache::CacheShard::acquireUIDSlot(
+    llvm::sys::fs::UniqueID UID) {
+  std::unique_lock<std::mutex> LockGuard(CacheLock);
+  // Cache hit.
+  if (auto It = EntriesByUID.find(UID); It != EntriesByUID.end())
+    return SlotAcquisitionResult{It->getSecond(), nullptr};
+
+  // Another worker is producing for this UID, wait for it.
+  if (auto It = InProgressByUID.find(UID); It != InProgressByUID.end()) {
+    std::shared_ptr<InProgressEntry> Pending = It->second;
+    Pending->CondVar.wait(LockGuard, [&] { return Pending->Done; });
+    assert(Pending->Result &&
+           "in-progress UID slot fulfilled without an entry");
+    return SlotAcquisitionResult{Pending->Result, nullptr};
+  }
+
+  // Install an in-progress entry and return it.
+  auto Pending = std::make_shared<InProgressEntry>();
+  InProgressByUID.try_emplace(UID, Pending);
+  return SlotAcquisitionResult{nullptr, std::move(Pending)};
+}
+
+void DependencyScanningFilesystemSharedCache::CacheShard::fulfilFilenameSlot(
+    StringRef Filename,
+    const std::shared_ptr<
+        DependencyScanningFilesystemSharedCache::InProgressEntry> &IPE,
+    const CachedFileSystemEntry *Result) {
+  {
+    std::lock_guard<std::mutex> LockGuard(CacheLock);
+    if (Result) {
+      // Publish the entry under this filename for future direct lookups,
+      // mirroring the semantics of getOrInsertEntryForFilename.
+      auto [It, Inserted] =
+          CacheByFilename.insert({Filename, {Result, nullptr}});
+      auto &[CachedEntry, CachedRealPath] = It->getValue();
+      if (!Inserted || !CachedEntry)
+        CachedEntry = Result;
+    }
+    IPE->Result = Result;
+    IPE->Done = true;
+    InProgressByFilename.erase(Filename);
+  }
+  // Notify other workers awaiting this result.
+  IPE->CondVar.notify_all();
+}
+
+void DependencyScanningFilesystemSharedCache::CacheShard::fulfilUIDSlot(
+    llvm::sys::fs::UniqueID UID,
+    const std::shared_ptr<
+        DependencyScanningFilesystemSharedCache::InProgressEntry> &IPE,
+    const CachedFileSystemEntry *Result) {
+  {
+    std::lock_guard<std::mutex> LockGuard(CacheLock);
+    if (Result) {
+      // Publish the entry under this UID.
+      auto [It, Inserted] = EntriesByUID.try_emplace(UID, Result);
+      if (!Inserted && !It->getSecond())
+        It->getSecond() = Result;
+    }
+    IPE->Result = Result;
+    IPE->Done = true;
+    InProgressByUID.erase(UID);
+  }
+  // Notify other workers awaiting this result.
+  IPE->CondVar.notify_all();
+}
+
 const CachedFileSystemEntry &
 DependencyScanningFilesystemSharedCache::CacheShard::getOrEmplaceEntryForUID(
     llvm::sys::fs::UniqueID UID, llvm::vfs::Status Stat,
@@ -262,44 +357,73 @@ 
DependencyScanningWorkerFilesystem::getOrEmplaceSharedEntryForUID(
                                        std::move(TEntry.Contents));
 }
 
-const CachedFileSystemEntry *
-DependencyScanningWorkerFilesystem::findEntryByFilenameWithWriteThrough(
-    StringRef Filename) {
-  if (const auto *Entry = LocalCache.findEntryByFilename(Filename))
-    return Entry;
-  auto &Shard = SharedCache.getShardForFilename(Filename);
-  if (const auto *Entry = Shard.findEntryByFilename(Filename))
-    return &LocalCache.insertEntryForFilename(Filename, *Entry);
-  return nullptr;
-}
-
 llvm::ErrorOr<const CachedFileSystemEntry &>
 DependencyScanningWorkerFilesystem::computeAndStoreResult(
     StringRef OriginalFilename, StringRef FilenameForLookup) {
-  llvm::ErrorOr<llvm::vfs::Status> Stat =
-      getUnderlyingFS().status(OriginalFilename);
-  if (!Stat) {
-    const auto &Entry =
-        getOrEmplaceSharedEntryForFilename(FilenameForLookup, Stat.getError());
-    return insertLocalEntryForFilename(FilenameForLookup, Entry);
-  }
-
-  if (const auto *Entry = findSharedEntryByUID(*Stat))
-    return insertLocalEntryForFilename(FilenameForLookup, *Entry);
-
-  auto TEntry =
-      Stat->isDirectory() ? TentativeEntry(*Stat) : readFile(OriginalFilename);
+  auto &FilenameShard = SharedCache.getShardForFilename(FilenameForLookup);
+
+  // Acquire a per-filename in-progress entry. If another worker has already
+  // produced an entry under this filename, or is currently producing one,
+  // adopt its result instead of duplicating the underlying filesystem.
+  auto FilenameSlot = FilenameShard.acquireFilenameSlot(FilenameForLookup);
+  if (FilenameSlot.Resolved)
+    return insertLocalEntryForFilename(FilenameForLookup,
+                                       *FilenameSlot.Resolved);
+
+  // Compute the result.
+  std::shared_ptr<DependencyScanningFilesystemSharedCache::InProgressEntry>
+      ProducerSlot = std::move(FilenameSlot.Produce);
+  const CachedFileSystemEntry *ProducedEntry = nullptr;
+  auto ComputeResult = [&]() -> llvm::ErrorOr<const CachedFileSystemEntry &> {
+    llvm::ErrorOr<llvm::vfs::Status> Stat =
+        getUnderlyingFS().status(OriginalFilename);
+    if (!Stat) {
+      const auto &Entry = getOrEmplaceSharedEntryForFilename(FilenameForLookup,
+                                                             Stat.getError());
+      ProducedEntry = &Entry;
+      return insertLocalEntryForFilename(FilenameForLookup, Entry);
+    }
 
-  const CachedFileSystemEntry *SharedEntry = [&]() {
-    if (TEntry) {
-      const auto &UIDEntry = getOrEmplaceSharedEntryForUID(std::move(*TEntry));
-      return &getOrInsertSharedEntryForFilename(FilenameForLookup, UIDEntry);
+    // Acquire a per-UID producer slot to dedup concurrent readFile()
+    // calls across workers that arrived under different filenames
+    // pointing at the same on-disk file.
+    auto &UIDShard = SharedCache.getShardForUID(Stat->getUniqueID());
+    auto UIDSlot = UIDShard.acquireUIDSlot(Stat->getUniqueID());
+    const CachedFileSystemEntry *SharedEntry = nullptr;
+    if (UIDSlot.Resolved) {
+      SharedEntry = UIDSlot.Resolved;
+    } else {
+      auto TEntry = Stat->isDirectory() ? TentativeEntry(*Stat)
+                                        : readFile(OriginalFilename);
+      if (TEntry) {
+        SharedEntry = &getOrEmplaceSharedEntryForUID(std::move(*TEntry));
+        // Publish the UID-keyed entry to anyone waiting on this UID.
+        UIDShard.fulfilUIDSlot(Stat->getUniqueID(), UIDSlot.Produce,
+                               SharedEntry);
+      } else {
+        // `readFile` failed despite `stat` succeeding. Cache
+        // the failure under the filename, and publish that same entry under
+        // the UID so that awaiting workers surface the error rather than 
racing
+        // to retry the open.
+        SharedEntry = &getOrEmplaceSharedEntryForFilename(FilenameForLookup,
+                                                          TEntry.getError());
+        UIDShard.fulfilUIDSlot(Stat->getUniqueID(), UIDSlot.Produce,
+                               SharedEntry);
+      }
     }
-    return &getOrEmplaceSharedEntryForFilename(FilenameForLookup,
-                                               TEntry.getError());
-  }();
 
-  return insertLocalEntryForFilename(FilenameForLookup, *SharedEntry);
+    // Bind the resolved/produced entry to this filename in the shared cache
+    // (idempotent if already there) and the local cache.
+    SharedEntry =
+        &getOrInsertSharedEntryForFilename(FilenameForLookup, *SharedEntry);
+    ProducedEntry = SharedEntry;
+    return insertLocalEntryForFilename(FilenameForLookup, *SharedEntry);
+  };
+
+  auto Result = ComputeResult();
+  FilenameShard.fulfilFilenameSlot(FilenameForLookup, ProducerSlot,
+                                   ProducedEntry);
+  return Result;
 }
 
 llvm::ErrorOr<EntryRef>
@@ -310,9 +434,9 @@ 
DependencyScanningWorkerFilesystem::getOrCreateFileSystemEntry(
   if (!FilenameForLookup)
     return FilenameForLookup.getError();
 
-  if (const auto *Entry =
-          findEntryByFilenameWithWriteThrough(*FilenameForLookup))
+  if (const auto *Entry = LocalCache.findEntryByFilename(*FilenameForLookup))
     return EntryRef(OriginalFilename, *Entry).unwrapError();
+
   auto MaybeEntry = computeAndStoreResult(OriginalFilename, 
*FilenameForLookup);
   if (!MaybeEntry)
     return MaybeEntry.getError();
diff --git 
a/clang/unittests/DependencyScanning/DependencyScanningFilesystemTest.cpp 
b/clang/unittests/DependencyScanning/DependencyScanningFilesystemTest.cpp
index d9489a9bf27ca..5dab80e61371f 100644
--- a/clang/unittests/DependencyScanning/DependencyScanningFilesystemTest.cpp
+++ b/clang/unittests/DependencyScanning/DependencyScanningFilesystemTest.cpp
@@ -10,9 +10,68 @@
 #include "llvm/ADT/SmallString.h"
 #include "llvm/Support/VirtualFileSystem.h"
 #include "gtest/gtest.h"
+#include <atomic>
+#include <condition_variable>
+#include <mutex>
+#include <thread>
 
 using namespace clang::dependencies;
 
+namespace {
+
+/// VFS proxy that counts operations using atomic counters, suitable for use
+/// from concurrent tests where `llvm::vfs::TracingFileSystem`'s plain
+/// `std::size_t` counters would race.
+class AtomicTracingFileSystem : public llvm::vfs::ProxyFileSystem {
+public:
+  std::atomic<size_t> NumStatusCalls{0};
+  std::atomic<size_t> NumOpenFileForReadCalls{0};
+  std::atomic<size_t> NumGetRealPathCalls{0};
+
+  AtomicTracingFileSystem(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS)
+      : ProxyFileSystem(std::move(FS)) {}
+
+  llvm::ErrorOr<llvm::vfs::Status> status(const llvm::Twine &Path) override {
+    ++NumStatusCalls;
+    return ProxyFileSystem::status(Path);
+  }
+
+  llvm::ErrorOr<std::unique_ptr<llvm::vfs::File>>
+  openFileForRead(const llvm::Twine &Path) override {
+    ++NumOpenFileForReadCalls;
+    return ProxyFileSystem::openFileForRead(Path);
+  }
+
+  std::error_code getRealPath(const llvm::Twine &Path,
+                              llvm::SmallVectorImpl<char> &Output) override {
+    ++NumGetRealPathCalls;
+    return ProxyFileSystem::getRealPath(Path, Output);
+  }
+};
+
+/// Releases all waiting threads simultaneously so that the worker logic can
+/// be observed under maximal concurrency rather than a thread-spawn cascade.
+struct StartBarrier {
+  std::mutex M;
+  std::condition_variable CV;
+  bool Released = false;
+
+  void wait() {
+    std::unique_lock<std::mutex> Lock(M);
+    CV.wait(Lock, [&] { return Released; });
+  }
+
+  void release() {
+    {
+      std::lock_guard<std::mutex> Lock(M);
+      Released = true;
+    }
+    CV.notify_all();
+  }
+};
+
+} // namespace
+
 TEST(DependencyScanningFilesystem, OpenFileAndGetBufferRepeatedly) {
   auto InMemoryFS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
   InMemoryFS->setCurrentWorkingDirectory("/");
@@ -286,3 +345,138 @@ TEST(DependencyScanningFilesystem, 
DoNotDiagnoseDirSizeChange) {
   auto InvalidEntries = SharedCache.getOutOfDateEntries(*FS);
   EXPECT_EQ(InvalidEntries.size(), 0u);
 }
+
+TEST(DependencyScanningWorkerFilesystem, ConcurrentSameFilenameDeduplicates) {
+  auto InMemoryFS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
+  InMemoryFS->setCurrentWorkingDirectory("/");
+  InMemoryFS->addFile("/foo.c", 0, llvm::MemoryBuffer::getMemBuffer("hello"));
+
+  auto TracingFS =
+      llvm::makeIntrusiveRefCnt<AtomicTracingFileSystem>(InMemoryFS);
+  DependencyScanningFilesystemSharedCache SharedCache;
+
+  constexpr unsigned NumWorkers = 16;
+  std::vector<std::unique_ptr<DependencyScanningWorkerFilesystem>> Workers;
+  Workers.reserve(NumWorkers);
+  for (unsigned I = 0; I < NumWorkers; ++I)
+    Workers.push_back(std::make_unique<DependencyScanningWorkerFilesystem>(
+        SharedCache, TracingFS));
+
+  StartBarrier Barrier;
+  std::vector<std::thread> Threads;
+  std::vector<llvm::ErrorOr<EntryRef>> Results(
+      NumWorkers, llvm::ErrorOr<EntryRef>(std::error_code{}));
+  Threads.reserve(NumWorkers);
+  for (unsigned I = 0; I < NumWorkers; ++I) {
+    Threads.emplace_back([&, I] {
+      Barrier.wait();
+      Results[I] = Workers[I]->getOrCreateFileSystemEntry("/foo.c");
+    });
+  }
+  Barrier.release();
+  for (auto &T : Threads)
+    T.join();
+
+  EXPECT_EQ(TracingFS->NumStatusCalls.load(), 1u);
+  EXPECT_EQ(TracingFS->NumOpenFileForReadCalls.load(), 1u);
+
+  // All workers must have observed the same underlying entry.
+  ASSERT_TRUE(Results[0]);
+  llvm::sys::fs::UniqueID FirstUID = Results[0]->getStatus().getUniqueID();
+  const char *FirstContents = Results[0]->getContents().data();
+  for (unsigned I = 0; I < NumWorkers; ++I) {
+    ASSERT_TRUE(Results[I]) << "worker " << I << " failed";
+    EXPECT_EQ(Results[I]->getStatus().getUniqueID(), FirstUID);
+    EXPECT_EQ(Results[I]->getContents().data(), FirstContents);
+  }
+}
+
+TEST(DependencyScanningWorkerFilesystem,
+     ConcurrentSameUIDDifferentFilenamesDeduplicatesOpen) {
+  auto InMemoryFS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
+  InMemoryFS->setCurrentWorkingDirectory("/");
+  InMemoryFS->addFile("/real.c", 0, llvm::MemoryBuffer::getMemBuffer("hi"));
+  ASSERT_TRUE(InMemoryFS->addHardLink("/alias.c", "/real.c"));
+
+  auto TracingFS =
+      llvm::makeIntrusiveRefCnt<AtomicTracingFileSystem>(InMemoryFS);
+  DependencyScanningFilesystemSharedCache SharedCache;
+
+  constexpr unsigned NumWorkers = 16;
+  std::vector<std::unique_ptr<DependencyScanningWorkerFilesystem>> Workers;
+  Workers.reserve(NumWorkers);
+  for (unsigned I = 0; I < NumWorkers; ++I)
+    Workers.push_back(std::make_unique<DependencyScanningWorkerFilesystem>(
+        SharedCache, TracingFS));
+
+  StartBarrier Barrier;
+  std::vector<std::thread> Threads;
+  std::vector<llvm::ErrorOr<EntryRef>> Results(
+      NumWorkers, llvm::ErrorOr<EntryRef>(std::error_code{}));
+  Threads.reserve(NumWorkers);
+  for (unsigned I = 0; I < NumWorkers; ++I) {
+    llvm::StringRef Path = (I % 2 == 0) ? "/real.c" : "/alias.c";
+    Threads.emplace_back([&, I, Path] {
+      Barrier.wait();
+      Results[I] = Workers[I]->getOrCreateFileSystemEntry(Path);
+    });
+  }
+  Barrier.release();
+  for (auto &T : Threads)
+    T.join();
+
+  // Each filename's slot dedupes its own stats; with two filenames we expect
+  // at most two stats. The UID slot then collapses the actual reads.
+  EXPECT_LE(TracingFS->NumStatusCalls.load(), 2u);
+  EXPECT_EQ(TracingFS->NumOpenFileForReadCalls.load(), 1u);
+
+  ASSERT_TRUE(Results[0]);
+  llvm::sys::fs::UniqueID FirstUID = Results[0]->getStatus().getUniqueID();
+  for (unsigned I = 0; I < NumWorkers; ++I) {
+    ASSERT_TRUE(Results[I]) << "worker " << I << " failed";
+    EXPECT_EQ(Results[I]->getStatus().getUniqueID(), FirstUID);
+  }
+}
+
+TEST(DependencyScanningWorkerFilesystem, ConcurrentNegativeStatDeduplicates) {
+  auto InMemoryFS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
+  InMemoryFS->setCurrentWorkingDirectory("/");
+  // Note: /missing.h is intentionally absent.
+
+  auto TracingFS =
+      llvm::makeIntrusiveRefCnt<AtomicTracingFileSystem>(InMemoryFS);
+  DependencyScanningFilesystemSharedCache SharedCache;
+
+  constexpr unsigned NumWorkers = 16;
+  std::vector<std::unique_ptr<DependencyScanningWorkerFilesystem>> Workers;
+  Workers.reserve(NumWorkers);
+  for (unsigned I = 0; I < NumWorkers; ++I)
+    Workers.push_back(std::make_unique<DependencyScanningWorkerFilesystem>(
+        SharedCache, TracingFS));
+
+  StartBarrier Barrier;
+  std::vector<std::thread> Threads;
+  std::vector<llvm::ErrorOr<llvm::vfs::Status>> Results(
+      NumWorkers, llvm::ErrorOr<llvm::vfs::Status>(std::error_code{}));
+  Threads.reserve(NumWorkers);
+  for (unsigned I = 0; I < NumWorkers; ++I) {
+    Threads.emplace_back([&, I] {
+      Barrier.wait();
+      Results[I] = Workers[I]->status("/missing.h");
+    });
+  }
+  Barrier.release();
+  for (auto &T : Threads)
+    T.join();
+
+  EXPECT_EQ(TracingFS->NumStatusCalls.load(), 1u);
+  EXPECT_EQ(TracingFS->NumOpenFileForReadCalls.load(), 0u);
+
+  // Every worker observed the same negative result.
+  ASSERT_FALSE(Results[0]);
+  std::error_code FirstError = Results[0].getError();
+  for (unsigned I = 0; I < NumWorkers; ++I) {
+    ASSERT_FALSE(Results[I]) << "worker " << I << " unexpectedly succeeded";
+    EXPECT_EQ(Results[I].getError(), FirstError);
+  }
+}

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to