Files
o3de/Code/Tools/AssetProcessor/native/FileWatcher/FileWatcher.h
T
Chris Burel ce0bb1ca2b [AssetProcessor] Refactor the FileWatcher to use only one watch thread
This change reworks the AssetProcessor's FileWatcher so that it only uses
one thread. This is motivated by getting better support for inotify on
Linux. The previous architecture required calling `inotify_init` once for
each directory that was being watched, and using separate inotify instances
for each watched tree. In addition, having separate threads per watched
tree is not necessary, and just consumes system resources. Each platform
supports watching multiple directories with the same platform-specific
watcher API, so each platform has been updated accordingly.

The interface to the FileWatcher class is greatly simplified. Previously,
it supported client-supplied filtering of the paths that would generate
notifications. This was done by subclassing `FolderWatchBase` and
implementing `OnFileChange`. However, only one filter was ever used, so
that filter is now hard-coded in the FileWatcher class, and the classes
driving the old filtering mechanism are removed. Users of the interface
now have a much easier time, they just call `AddFolderWatch` with the path
to watch, and only have to connect to one set of signals, instead of
separate signals per watched directory.

Signed-off-by: Chris Burel <burelc@amazon.com>
2022-01-04 16:12:17 -08:00

79 lines
2.3 KiB
C++

/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#if !defined(Q_MOC_RUN)
#include <AzCore/std/smart_ptr/unique_ptr.h>
#include <AzCore/std/containers/vector.h>
#include <AzCore/std/parallel/atomic.h>
#include <AzCore/std/parallel/thread.h>
#include <QMap>
#include <QVector>
#include <QString>
#include <QObject>
#endif
//////////////////////////////////////////////////////////////////////////
//! FileWatcher
/*! Class that handles creation and deletion of FolderRootWatches based on
*! the given FolderWatches, and forwards file change signals to them.
* */
class FileWatcher
: public QObject
{
Q_OBJECT
public:
FileWatcher();
~FileWatcher() override;
//////////////////////////////////////////////////////////////////////////
void AddFolderWatch(QString directory, bool recursive = true);
void ClearFolderWatches();
//////////////////////////////////////////////////////////////////////////
void StartWatching();
void StopWatching();
Q_SIGNALS:
// These signals are emitted when a file under a watched path changes
void fileAdded(QString filePath);
void fileRemoved(QString filePath);
void fileModified(QString filePath);
// These signals are emitted by the platform implementations when files
// change. Some platforms' file watch APIs do not support non-recursive
// watches, so the signals are filtered before being forwarded to the
// non-"raw" fileAdded/Removed/Modified signals above.
void rawFileAdded(QString filePath, QPrivateSignal);
void rawFileRemoved(QString filePath, QPrivateSignal);
void rawFileModified(QString filePath, QPrivateSignal);
private:
bool PlatformStart();
void PlatformStop();
void WatchFolderLoop();
class PlatformImplementation;
friend class PlatformImplementation;
struct WatchRoot
{
QString m_directory;
bool m_recursive;
};
static bool Filter(QString path, const WatchRoot& watchRoot);
AZStd::unique_ptr<PlatformImplementation> m_platformImpl;
AZStd::vector<WatchRoot> m_folderWatchRoots;
AZStd::thread m_thread;
bool m_startedWatching = false;
AZStd::atomic_bool m_shutdownThreadSignal = false;
};