#3425: Fixed suspend/resumeEvents pair in DirectoryWatcher

This commit is contained in:
Günter Obiltschnig
2021-11-05 15:05:01 +01:00
parent a032f771af
commit 58fd4fcd6a
3 changed files with 198 additions and 59 deletions

View File

@@ -61,7 +61,7 @@ public:
{
return _owner;
}
virtual void run() = 0;
virtual void stop() = 0;
virtual bool supportsMoveEvents() const = 0;
@@ -73,21 +73,21 @@ protected:
size(0)
{
}
ItemInfo(const ItemInfo& other):
path(other.path),
size(other.size),
lastModified(other.lastModified)
{
}
explicit ItemInfo(const File& f):
path(f.path()),
size(f.isFile() ? f.getSize() : 0),
lastModified(f.getLastModified())
{
}
std::string path;
File::FileSize size;
Timestamp lastModified;
@@ -104,7 +104,7 @@ protected:
++it;
}
}
void compare(ItemInfoMap& oldEntries, ItemInfoMap& newEntries)
{
for (auto& np: newEntries)
@@ -145,7 +145,7 @@ private:
DirectoryWatcherStrategy();
DirectoryWatcherStrategy(const DirectoryWatcherStrategy&);
DirectoryWatcherStrategy& operator = (const DirectoryWatcherStrategy&);
DirectoryWatcher& _owner;
};
@@ -163,21 +163,21 @@ public:
if (!_hStopped)
throw SystemException("cannot create event");
}
~WindowsDirectoryWatcherStrategy()
{
CloseHandle(_hStopped);
}
void run()
{
ItemInfoMap entries;
scan(entries);
DWORD filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
if (owner().eventMask() & DirectoryWatcher::DW_ITEM_MODIFIED)
filter |= FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE;
std::string path(owner().directory().path());
std::wstring upath;
FileImpl::convertPath(path.c_str(), upath);
@@ -195,7 +195,7 @@ public:
}
return;
}
bool stopped = false;
while (!stopped)
{
@@ -228,21 +228,21 @@ public:
catch (Poco::Exception& exc)
{
owner().scanError(&owner(), exc);
}
}
}
FindCloseChangeNotification(hChange);
}
void stop()
{
SetEvent(_hStopped);
}
bool supportsMoveEvents() const
{
return false;
}
private:
HANDLE _hStopped;
};
@@ -262,12 +262,12 @@ public:
_fd = inotify_init();
if (_fd == -1) throw Poco::IOException("cannot initialize inotify", errno);
}
~LinuxDirectoryWatcherStrategy()
{
close(_fd);
}
void run()
{
int mask = 0;
@@ -293,7 +293,7 @@ public:
owner().scanError(&owner(), exc);
}
}
Poco::Buffer<char> buffer(4096);
while (!_stopped)
{
@@ -314,16 +314,16 @@ public:
while (n > 0)
{
struct inotify_event* pEvent = reinterpret_cast<struct inotify_event*>(buffer.begin() + i);
if (pEvent->len > 0)
{
{
if (!owner().eventsSuspended())
{
Poco::Path p(owner().directory().path());
p.makeDirectory();
p.setFileName(pEvent->name);
Poco::File f(p.toString());
if ((pEvent->mask & IN_CREATE) && (owner().eventMask() & DirectoryWatcher::DW_ITEM_ADDED))
{
DirectoryWatcher::DirectoryEvent ev(f, DirectoryWatcher::DW_ITEM_ADDED);
@@ -351,7 +351,7 @@ public:
}
}
}
i += sizeof(inotify_event) + pEvent->len;
n -= sizeof(inotify_event) + pEvent->len;
}
@@ -359,12 +359,12 @@ public:
}
}
}
void stop()
{
_stopped = true;
}
bool supportsMoveEvents() const
{
return true;
@@ -469,11 +469,11 @@ public:
DirectoryWatcherStrategy(owner)
{
}
~PollingDirectoryWatcherStrategy()
{
}
void run()
{
ItemInfoMap entries;
@@ -493,7 +493,7 @@ public:
}
}
}
void stop()
{
_stopped.set();
@@ -520,7 +520,7 @@ DirectoryWatcher::DirectoryWatcher(const std::string& path, int eventMask, int s
init();
}
DirectoryWatcher::DirectoryWatcher(const Poco::File& directory, int eventMask, int scanInterval):
_directory(directory),
_eventMask(eventMask),
@@ -543,16 +543,16 @@ DirectoryWatcher::~DirectoryWatcher()
}
}
void DirectoryWatcher::suspendEvents()
void DirectoryWatcher::resumeEvents()
{
poco_assert (_eventsSuspended > 0);
_eventsSuspended--;
}
void DirectoryWatcher::resumeEvents()
void DirectoryWatcher::suspendEvents()
{
_eventsSuspended++;
}
@@ -562,7 +562,7 @@ void DirectoryWatcher::init()
{
if (!_directory.exists())
throw Poco::FileNotFoundException(_directory.path());
if (!_directory.isDirectory())
throw Poco::InvalidArgumentException("not a directory", _directory.path());
@@ -578,7 +578,7 @@ void DirectoryWatcher::init()
_thread.start(*this);
}
void DirectoryWatcher::run()
{
_pStrategy->run();

View File

@@ -24,7 +24,7 @@
using Poco::DirectoryWatcher;
DirectoryWatcherTest::DirectoryWatcherTest(const std::string& name):
DirectoryWatcherTest::DirectoryWatcherTest(const std::string& name):
CppUnit::TestCase(name),
_error(false)
{
@@ -39,23 +39,23 @@ DirectoryWatcherTest::~DirectoryWatcherTest()
void DirectoryWatcherTest::testAdded()
{
DirectoryWatcher dw(path().toString(), DirectoryWatcher::DW_FILTER_ENABLE_ALL, 2);
dw.itemAdded += Poco::delegate(this, &DirectoryWatcherTest::onItemAdded);
dw.itemRemoved += Poco::delegate(this, &DirectoryWatcherTest::onItemRemoved);
dw.itemModified += Poco::delegate(this, &DirectoryWatcherTest::onItemModified);
dw.itemMovedFrom += Poco::delegate(this, &DirectoryWatcherTest::onItemMovedFrom);
dw.itemMovedTo += Poco::delegate(this, &DirectoryWatcherTest::onItemMovedTo);
Poco::Thread::sleep(1000);
Poco::Path p(path());
p.setFileName("test.txt");
Poco::FileOutputStream fos(p.toString());
fos << "Hello, world!";
fos.close();
Poco::Thread::sleep(2000*dw.scanInterval());
assertTrue (_events.size() >= 1);
assertTrue (_events[0].callback == "onItemAdded");
assertTrue (Poco::Path(_events[0].path).getFileName() == "test.txt");
@@ -73,20 +73,20 @@ void DirectoryWatcherTest::testRemoved()
fos.close();
DirectoryWatcher dw(path().toString(), DirectoryWatcher::DW_FILTER_ENABLE_ALL, 2);
dw.itemAdded += Poco::delegate(this, &DirectoryWatcherTest::onItemAdded);
dw.itemRemoved += Poco::delegate(this, &DirectoryWatcherTest::onItemRemoved);
dw.itemModified += Poco::delegate(this, &DirectoryWatcherTest::onItemModified);
dw.itemMovedFrom += Poco::delegate(this, &DirectoryWatcherTest::onItemMovedFrom);
dw.itemMovedTo += Poco::delegate(this, &DirectoryWatcherTest::onItemMovedTo);
Poco::Thread::sleep(1000);
Poco::File f(p.toString());
f.remove();
Poco::Thread::sleep(2000*dw.scanInterval());
assertTrue (_events.size() >= 1);
assertTrue (_events[0].callback == "onItemRemoved");
assertTrue (Poco::Path(_events[0].path).getFileName() == "test.txt");
@@ -104,21 +104,21 @@ void DirectoryWatcherTest::testModified()
fos.close();
DirectoryWatcher dw(path().toString(), DirectoryWatcher::DW_FILTER_ENABLE_ALL, 2);
dw.itemAdded += Poco::delegate(this, &DirectoryWatcherTest::onItemAdded);
dw.itemRemoved += Poco::delegate(this, &DirectoryWatcherTest::onItemRemoved);
dw.itemModified += Poco::delegate(this, &DirectoryWatcherTest::onItemModified);
dw.itemMovedFrom += Poco::delegate(this, &DirectoryWatcherTest::onItemMovedFrom);
dw.itemMovedTo += Poco::delegate(this, &DirectoryWatcherTest::onItemMovedTo);
Poco::Thread::sleep(1000);
Poco::FileOutputStream fos2(p.toString(), std::ios::app);
fos2 << "Again!";
fos2.close();
Poco::Thread::sleep(2000*dw.scanInterval());
assertTrue (_events.size() >= 1);
assertTrue (_events[0].callback == "onItemModified");
assertTrue (Poco::Path(_events[0].path).getFileName() == "test.txt");
@@ -136,22 +136,22 @@ void DirectoryWatcherTest::testMoved()
fos.close();
DirectoryWatcher dw(path().toString(), DirectoryWatcher::DW_FILTER_ENABLE_ALL, 2);
dw.itemAdded += Poco::delegate(this, &DirectoryWatcherTest::onItemAdded);
dw.itemRemoved += Poco::delegate(this, &DirectoryWatcherTest::onItemRemoved);
dw.itemModified += Poco::delegate(this, &DirectoryWatcherTest::onItemModified);
dw.itemMovedFrom += Poco::delegate(this, &DirectoryWatcherTest::onItemMovedFrom);
dw.itemMovedTo += Poco::delegate(this, &DirectoryWatcherTest::onItemMovedTo);
Poco::Thread::sleep(1000);
Poco::Path p2(path());
p2.setFileName("test2.txt");
Poco::File f(p.toString());
f.renameTo(p2.toString());
Poco::Thread::sleep(2000*dw.scanInterval());
if (dw.supportsMoveEvents())
{
assertTrue (_events.size() >= 2);
@@ -188,11 +188,144 @@ void DirectoryWatcherTest::testMoved()
}
void DirectoryWatcherTest::testSuspend()
{
Poco::Path p(path());
p.setFileName("test.txt");
Poco::FileOutputStream fos(p.toString());
fos << "Hello, world!";
fos.close();
DirectoryWatcher dw(path().toString(), DirectoryWatcher::DW_FILTER_ENABLE_ALL, 2);
dw.itemAdded += Poco::delegate(this, &DirectoryWatcherTest::onItemAdded);
dw.itemRemoved += Poco::delegate(this, &DirectoryWatcherTest::onItemRemoved);
dw.itemModified += Poco::delegate(this, &DirectoryWatcherTest::onItemModified);
dw.itemMovedFrom += Poco::delegate(this, &DirectoryWatcherTest::onItemMovedFrom);
dw.itemMovedTo += Poco::delegate(this, &DirectoryWatcherTest::onItemMovedTo);
Poco::Thread::sleep(1000);
dw.suspendEvents();
Poco::FileOutputStream fos2(p.toString(), std::ios::app);
fos2 << "Again!";
fos2.close();
Poco::Thread::sleep(2000*dw.scanInterval());
assertTrue (_events.size() == 0);
assertTrue (!_error);
}
void DirectoryWatcherTest::testResume()
{
Poco::Path p(path());
p.setFileName("test.txt");
Poco::FileOutputStream fos(p.toString());
fos << "Hello, world!";
fos.close();
DirectoryWatcher dw(path().toString(), DirectoryWatcher::DW_FILTER_ENABLE_ALL, 2);
dw.itemAdded += Poco::delegate(this, &DirectoryWatcherTest::onItemAdded);
dw.itemRemoved += Poco::delegate(this, &DirectoryWatcherTest::onItemRemoved);
dw.itemModified += Poco::delegate(this, &DirectoryWatcherTest::onItemModified);
dw.itemMovedFrom += Poco::delegate(this, &DirectoryWatcherTest::onItemMovedFrom);
dw.itemMovedTo += Poco::delegate(this, &DirectoryWatcherTest::onItemMovedTo);
Poco::Thread::sleep(1000);
dw.suspendEvents();
Poco::FileOutputStream fos2(p.toString(), std::ios::app);
fos2 << "Again!";
fos2.close();
assertTrue (_events.size() == 0);
assertTrue (!_error);
dw.resumeEvents();
Poco::FileOutputStream fos3(p.toString(), std::ios::app);
fos3 << "Now it works!";
fos3.close();
Poco::Thread::sleep(2000*dw.scanInterval());
assertTrue (_events.size() >= 1);
assertTrue (_events[0].callback == "onItemModified");
assertTrue (Poco::Path(_events[0].path).getFileName() == "test.txt");
assertTrue (_events[0].type == DirectoryWatcher::DW_ITEM_MODIFIED);
assertTrue (!_error);
}
void DirectoryWatcherTest::testSuspendMultipleTimes()
{
Poco::Path p(path());
p.setFileName("test.txt");
Poco::FileOutputStream fos(p.toString());
fos << "Hello, world!";
fos.close();
DirectoryWatcher dw(path().toString(), DirectoryWatcher::DW_FILTER_ENABLE_ALL, 2);
dw.itemAdded += Poco::delegate(this, &DirectoryWatcherTest::onItemAdded);
dw.itemRemoved += Poco::delegate(this, &DirectoryWatcherTest::onItemRemoved);
dw.itemModified += Poco::delegate(this, &DirectoryWatcherTest::onItemModified);
dw.itemMovedFrom += Poco::delegate(this, &DirectoryWatcherTest::onItemMovedFrom);
dw.itemMovedTo += Poco::delegate(this, &DirectoryWatcherTest::onItemMovedTo);
Poco::Thread::sleep(1000);
dw.suspendEvents();
dw.suspendEvents();
dw.suspendEvents();
Poco::FileOutputStream fos2(p.toString(), std::ios::app);
fos2 << "Not notified!";
fos2.close();
Poco::Thread::sleep(2000*dw.scanInterval());
assertTrue (_events.size() == 0);
assertTrue (!_error);
dw.resumeEvents();
Poco::FileOutputStream fos3(p.toString(), std::ios::app);
fos3 << "Still not notified!";
fos3.close();
Poco::Thread::sleep(2000*dw.scanInterval());
assertTrue (_events.size() == 0);
assertTrue (!_error);
dw.resumeEvents();
dw.resumeEvents();
Poco::FileOutputStream fos4(p.toString(), std::ios::app);
fos4 << "Now it works!";
fos4.close();
Poco::Thread::sleep(2000*dw.scanInterval());
assertTrue (_events.size() >= 1);
assertTrue (_events[0].callback == "onItemModified");
assertTrue (Poco::Path(_events[0].path).getFileName() == "test.txt");
assertTrue (_events[0].type == DirectoryWatcher::DW_ITEM_MODIFIED);
assertTrue (!_error);
}
void DirectoryWatcherTest::setUp()
{
_error = false;
_events.clear();
try
{
Poco::File d(path().toString());
@@ -292,6 +425,9 @@ CppUnit::Test* DirectoryWatcherTest::suite()
CppUnit_addTest(pSuite, DirectoryWatcherTest, testRemoved);
CppUnit_addTest(pSuite, DirectoryWatcherTest, testModified);
CppUnit_addTest(pSuite, DirectoryWatcherTest, testMoved);
CppUnit_addTest(pSuite, DirectoryWatcherTest, testSuspend);
CppUnit_addTest(pSuite, DirectoryWatcherTest, testResume);
CppUnit_addTest(pSuite, DirectoryWatcherTest, testSuspendMultipleTimes);
return pSuite;
}

View File

@@ -35,12 +35,15 @@ public:
void testRemoved();
void testModified();
void testMoved();
void testSuspend();
void testResume();
void testSuspendMultipleTimes();
void setUp();
void tearDown();
static CppUnit::Test* suite();
protected:
void onItemAdded(const Poco::DirectoryWatcher::DirectoryEvent& ev);
void onItemRemoved(const Poco::DirectoryWatcher::DirectoryEvent& ev);
@@ -48,7 +51,7 @@ protected:
void onItemMovedFrom(const Poco::DirectoryWatcher::DirectoryEvent& ev);
void onItemMovedTo(const Poco::DirectoryWatcher::DirectoryEvent& ev);
void onError(const Poco::Exception& exc);
Poco::Path path() const;
private: