From 04f4d5e0318eac4d01f8f72e5a2b06a0da6d5388 Mon Sep 17 00:00:00 2001 From: Chris Burel Date: Tue, 26 Oct 2021 16:36:35 -0700 Subject: [PATCH] [Linux] Avoid recursive inotify when a watch folder is set to recursive=false Signed-off-by: Chris Burel --- .../native/FileWatcher/FileWatcher_linux.cpp | 31 +++++++++++++++---- .../native/FileWatcher/FileWatcher.cpp | 6 ++-- .../native/FileWatcher/FileWatcher.h | 5 +-- .../utilities/ApplicationManagerBase.cpp | 2 +- 4 files changed, 32 insertions(+), 12 deletions(-) diff --git a/Code/Tools/AssetProcessor/Platform/Linux/native/FileWatcher/FileWatcher_linux.cpp b/Code/Tools/AssetProcessor/Platform/Linux/native/FileWatcher/FileWatcher_linux.cpp index b7f7affd6d..f63282abfc 100644 --- a/Code/Tools/AssetProcessor/Platform/Linux/native/FileWatcher/FileWatcher_linux.cpp +++ b/Code/Tools/AssetProcessor/Platform/Linux/native/FileWatcher/FileWatcher_linux.cpp @@ -63,7 +63,7 @@ struct FolderRootWatch::PlatformImplementation } } - void AddWatchFolder(QString folder) + void AddWatchFolder(QString folder, bool recursive) { if (m_iNotifyHandle >= 0) { @@ -75,6 +75,11 @@ struct FolderRootWatch::PlatformImplementation cleanPath.toUtf8().constData(), IN_CREATE | IN_CLOSE_WRITE | IN_DELETE | IN_DELETE_SELF | IN_MODIFY | IN_MOVE); + if (watchHandle < 0) + { + AZ_Error("FileWatcher", false, "inotify_add_watch failed for path %s", cleanPath.toUtf8().constData()); + return; + } if (!m_handleToFolderMapLock.tryLock(s_handleToFolderMapLockTimeout)) { AZ_Error("FileWatcher", false, "Unable to obtain inotify handle lock on thread"); @@ -83,6 +88,11 @@ struct FolderRootWatch::PlatformImplementation m_handleToFolderMap[watchHandle] = cleanPath; m_handleToFolderMapLock.unlock(); + if (!recursive) + { + return; + } + // Add all the subfolders to watch and track them QDirIterator dirIter(folder, QDirIterator::Subdirectories | QDirIterator::FollowSymlinks); @@ -97,6 +107,11 @@ struct FolderRootWatch::PlatformImplementation int watchHandle = inotify_add_watch(m_iNotifyHandle, dirName.toUtf8().constData(), IN_CREATE | IN_CLOSE_WRITE | IN_DELETE | IN_DELETE_SELF | IN_MODIFY | IN_MOVE); + if (watchHandle < 0) + { + AZ_Error("FileWatcher", false, "inotify_add_watch failed for path %s", dirName.toUtf8().constData()); + return; + } if (!m_handleToFolderMapLock.tryLock(s_handleToFolderMapLockTimeout)) { @@ -133,10 +148,11 @@ struct FolderRootWatch::PlatformImplementation ////////////////////////////////////////////////////////////////////////////// /// FolderWatchRoot -FolderRootWatch::FolderRootWatch(const QString rootFolder) +FolderRootWatch::FolderRootWatch(const QString rootFolder, bool recursive) : m_root(rootFolder) , m_shutdownThreadSignal(false) , m_fileWatcher(nullptr) + , m_recursive(recursive) , m_platformImpl(new PlatformImplementation()) { } @@ -156,10 +172,13 @@ bool FolderRootWatch::Start() { return false; } - m_platformImpl->AddWatchFolder(m_root); + m_platformImpl->AddWatchFolder(m_root, m_recursive); m_shutdownThreadSignal = false; - m_thread = std::thread([this]() { WatchFolderLoop(); }); + if (m_platformImpl->m_iNotifyHandle >= 0) + { + m_thread = std::thread([this]() { WatchFolderLoop(); }); + } return true; } @@ -200,10 +219,10 @@ void FolderRootWatch::WatchFolderLoop() if (event->mask & (IN_CREATE | IN_MOVED_TO)) { - if ( event->mask & IN_ISDIR ) + if ( event->mask & IN_ISDIR && m_recursive) { // New Directory, add it to the watch - m_platformImpl->AddWatchFolder(pathStr); + m_platformImpl->AddWatchFolder(pathStr, true); } else { diff --git a/Code/Tools/AssetProcessor/native/FileWatcher/FileWatcher.cpp b/Code/Tools/AssetProcessor/native/FileWatcher/FileWatcher.cpp index ff9876ebdd..4d4b4e9690 100644 --- a/Code/Tools/AssetProcessor/native/FileWatcher/FileWatcher.cpp +++ b/Code/Tools/AssetProcessor/native/FileWatcher/FileWatcher.cpp @@ -49,7 +49,7 @@ FileWatcher::~FileWatcher() { } -int FileWatcher::AddFolderWatch(FolderWatchBase* pFolderWatch) +int FileWatcher::AddFolderWatch(FolderWatchBase* pFolderWatch, bool recursive) { if (!pFolderWatch) { @@ -72,7 +72,7 @@ int FileWatcher::AddFolderWatch(FolderWatchBase* pFolderWatch) if (!pFolderRootWatch) { //create a new root and start listening for changes - pFolderRootWatch = new FolderRootWatch(pFolderWatch->m_folder); + pFolderRootWatch = new FolderRootWatch(pFolderWatch->m_folder, recursive); //make sure the folder watcher(s) get deleted before this pFolderRootWatch->setParent(this); @@ -93,7 +93,7 @@ int FileWatcher::AddFolderWatch(FolderWatchBase* pFolderWatch) //of other roots, if it is then then fold those roots into the new super root for (auto rootsIter = m_folderWatchRoots.begin(); rootsIter != m_folderWatchRoots.end(); ) { - if (FolderWatchBase::IsSubfolder((*rootsIter)->m_root, pFolderWatch->m_folder)) + if (pFolderWatch->m_watchSubtree && FolderWatchBase::IsSubfolder((*rootsIter)->m_root, pFolderWatch->m_folder)) { //union the sub folder map over to the new root pFolderRootWatch->m_subFolderWatchesMap.insert((*rootsIter)->m_subFolderWatchesMap); diff --git a/Code/Tools/AssetProcessor/native/FileWatcher/FileWatcher.h b/Code/Tools/AssetProcessor/native/FileWatcher/FileWatcher.h index 392f8194a6..fc3f109604 100644 --- a/Code/Tools/AssetProcessor/native/FileWatcher/FileWatcher.h +++ b/Code/Tools/AssetProcessor/native/FileWatcher/FileWatcher.h @@ -33,7 +33,7 @@ class FolderRootWatch friend class FileWatcher; public: - FolderRootWatch(const QString rootFolder); + FolderRootWatch(const QString rootFolder, bool recursive = true); virtual ~FolderRootWatch(); void ProcessNewFileEvent(const QString& file); @@ -54,6 +54,7 @@ private: QMap m_subFolderWatchesMap; volatile bool m_shutdownThreadSignal; FileWatcher* m_fileWatcher; + bool m_recursive; // Can't use unique_ptr because this is a QObject and Qt's magic sauce is // unable to determine the size of the unique_ptr and so fails to compile @@ -76,7 +77,7 @@ public: virtual ~FileWatcher(); ////////////////////////////////////////////////////////////////////////// - virtual int AddFolderWatch(FolderWatchBase* pFolderWatch); + virtual int AddFolderWatch(FolderWatchBase* pFolderWatch, bool recursive = true); virtual void RemoveFolderWatch(int handle); ////////////////////////////////////////////////////////////////////////// diff --git a/Code/Tools/AssetProcessor/native/utilities/ApplicationManagerBase.cpp b/Code/Tools/AssetProcessor/native/utilities/ApplicationManagerBase.cpp index 04036602db..f9827bda2e 100644 --- a/Code/Tools/AssetProcessor/native/utilities/ApplicationManagerBase.cpp +++ b/Code/Tools/AssetProcessor/native/utilities/ApplicationManagerBase.cpp @@ -461,7 +461,7 @@ void ApplicationManagerBase::InitFileMonitor() m_fileProcessor.get(), &AssetProcessor::FileProcessor::AssessDeletedFile); m_folderWatches.push_back(AZStd::unique_ptr(newFolderWatch)); - m_watchHandles.push_back(m_fileWatcher.AddFolderWatch(newFolderWatch)); + m_watchHandles.push_back(m_fileWatcher.AddFolderWatch(newFolderWatch, info.RecurseSubFolders())); } // also hookup monitoring for the cache (output directory)