mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-21 15:12:02 +00:00
Remove select() usage
This commit is contained in:
parent
adbc819a09
commit
73ff984755
@ -30,7 +30,6 @@ int __gai_sigqueue(int sig, const union sigval val, pid_t caller_pid)
|
||||
}
|
||||
|
||||
|
||||
#include <sys/select.h>
|
||||
#include <stdlib.h>
|
||||
#include <features.h>
|
||||
|
||||
|
@ -55,7 +55,6 @@ set (SRCS
|
||||
src/DigestStream.cpp
|
||||
src/DirectoryIterator.cpp
|
||||
src/DirectoryIteratorStrategy.cpp
|
||||
src/DirectoryWatcher.cpp
|
||||
src/Environment.cpp
|
||||
src/Error.cpp
|
||||
src/ErrorHandler.cpp
|
||||
|
@ -1,228 +0,0 @@
|
||||
//
|
||||
// DirectoryWatcher.h
|
||||
//
|
||||
// Library: Foundation
|
||||
// Package: Filesystem
|
||||
// Module: DirectoryWatcher
|
||||
//
|
||||
// Definition of the DirectoryWatcher class.
|
||||
//
|
||||
// Copyright (c) 2012, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#ifndef Foundation_DirectoryWatcher_INCLUDED
|
||||
#define Foundation_DirectoryWatcher_INCLUDED
|
||||
|
||||
|
||||
#include "Poco/Foundation.h"
|
||||
|
||||
|
||||
#ifndef POCO_NO_INOTIFY
|
||||
|
||||
|
||||
# include "Poco/AtomicCounter.h"
|
||||
# include "Poco/BasicEvent.h"
|
||||
# include "Poco/File.h"
|
||||
# include "Poco/Runnable.h"
|
||||
# include "Poco/Thread.h"
|
||||
|
||||
|
||||
namespace Poco
|
||||
{
|
||||
|
||||
|
||||
class DirectoryWatcherStrategy;
|
||||
|
||||
|
||||
class Foundation_API DirectoryWatcher : protected Runnable
|
||||
/// This class is used to get notifications about changes
|
||||
/// to the filesystem, more specifically, to a specific
|
||||
/// directory. Changes to a directory are reported via
|
||||
/// events.
|
||||
///
|
||||
/// A thread will be created that watches the specified
|
||||
/// directory for changes. Events are reported in the context
|
||||
/// of this thread.
|
||||
///
|
||||
/// Note that changes to files in subdirectories of the watched
|
||||
/// directory are not reported. Separate DirectoryWatcher objects
|
||||
/// must be created for these directories if they should be watched.
|
||||
///
|
||||
/// Changes to file attributes are not reported.
|
||||
///
|
||||
/// On Windows, this class is implemented using FindFirstChangeNotification()/FindNextChangeNotification().
|
||||
/// On Linux, this class is implemented using inotify.
|
||||
/// On FreeBSD and Darwin (Mac OS X, iOS), this class uses kevent/kqueue.
|
||||
/// On all other platforms, the watched directory is periodically scanned
|
||||
/// for changes. This can negatively affect performance if done too often.
|
||||
/// Therefore, the interval in which scans are done can be specified in
|
||||
/// the constructor. Note that periodic scanning will also be done on FreeBSD
|
||||
/// and Darwin if events for changes to files (DW_ITEM_MODIFIED) are enabled.
|
||||
///
|
||||
/// DW_ITEM_MOVED_FROM and DW_ITEM_MOVED_TO events will only be reported
|
||||
/// on Linux. On other platforms, a file rename or move operation
|
||||
/// will be reported via a DW_ITEM_REMOVED and a DW_ITEM_ADDED event.
|
||||
/// The order of these two events is not defined.
|
||||
///
|
||||
/// An event mask can be specified to enable only certain events.
|
||||
{
|
||||
public:
|
||||
enum DirectoryEventType
|
||||
{
|
||||
DW_ITEM_ADDED = 1,
|
||||
/// A new item has been created and added to the directory.
|
||||
|
||||
DW_ITEM_REMOVED = 2,
|
||||
/// An item has been removed from the directory.
|
||||
|
||||
DW_ITEM_MODIFIED = 4,
|
||||
/// An item has been modified.
|
||||
|
||||
DW_ITEM_MOVED_FROM = 8,
|
||||
/// An item has been renamed or moved. This event delivers the old name.
|
||||
|
||||
DW_ITEM_MOVED_TO = 16
|
||||
/// An item has been renamed or moved. This event delivers the new name.
|
||||
};
|
||||
|
||||
enum DirectoryEventMask
|
||||
{
|
||||
DW_FILTER_ENABLE_ALL = 31,
|
||||
/// Enables all event types.
|
||||
|
||||
DW_FILTER_DISABLE_ALL = 0
|
||||
/// Disables all event types.
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
DW_DEFAULT_SCAN_INTERVAL = 5 /// Default scan interval for platforms that don't provide a native notification mechanism.
|
||||
};
|
||||
|
||||
struct DirectoryEvent
|
||||
{
|
||||
DirectoryEvent(const File & f, DirectoryEventType ev) : item(f), event(ev) { }
|
||||
|
||||
const File & item; /// The directory or file that has been changed.
|
||||
DirectoryEventType event; /// The kind of event.
|
||||
};
|
||||
|
||||
BasicEvent<const DirectoryEvent> itemAdded;
|
||||
/// Fired when a file or directory has been created or added to the directory.
|
||||
|
||||
BasicEvent<const DirectoryEvent> itemRemoved;
|
||||
/// Fired when a file or directory has been removed from the directory.
|
||||
|
||||
BasicEvent<const DirectoryEvent> itemModified;
|
||||
/// Fired when a file or directory has been modified.
|
||||
|
||||
BasicEvent<const DirectoryEvent> itemMovedFrom;
|
||||
/// Fired when a file or directory has been renamed. This event delivers the old name.
|
||||
|
||||
BasicEvent<const DirectoryEvent> itemMovedTo;
|
||||
/// Fired when a file or directory has been moved. This event delivers the new name.
|
||||
|
||||
BasicEvent<const Exception> scanError;
|
||||
/// Fired when an error occurs while scanning for changes.
|
||||
|
||||
DirectoryWatcher(const std::string & path, int eventMask = DW_FILTER_ENABLE_ALL, int scanInterval = DW_DEFAULT_SCAN_INTERVAL);
|
||||
/// Creates a DirectoryWatcher for the directory given in path.
|
||||
/// To enable only specific events, an eventMask can be specified by
|
||||
/// OR-ing the desired event IDs (e.g., DW_ITEM_ADDED | DW_ITEM_MODIFIED).
|
||||
/// On platforms where no native filesystem notifications are available,
|
||||
/// scanInterval specifies the interval in seconds between scans
|
||||
/// of the directory.
|
||||
|
||||
DirectoryWatcher(const File & directory, int eventMask = DW_FILTER_ENABLE_ALL, int scanInterval = DW_DEFAULT_SCAN_INTERVAL);
|
||||
/// Creates a DirectoryWatcher for the specified directory
|
||||
/// To enable only specific events, an eventMask can be specified by
|
||||
/// OR-ing the desired event IDs (e.g., DW_ITEM_ADDED | DW_ITEM_MODIFIED).
|
||||
/// On platforms where no native filesystem notifications are available,
|
||||
/// scanInterval specifies the interval in seconds between scans
|
||||
/// of the directory.
|
||||
|
||||
~DirectoryWatcher();
|
||||
/// Destroys the DirectoryWatcher.
|
||||
|
||||
void suspendEvents();
|
||||
/// Suspends sending of events. Can be called multiple times, but every
|
||||
/// call to suspendEvent() must be matched by a call to resumeEvents().
|
||||
|
||||
void resumeEvents();
|
||||
/// Resumes events, after they have been suspended with a call to suspendEvents().
|
||||
|
||||
bool eventsSuspended() const;
|
||||
/// Returns true iff events are suspended.
|
||||
|
||||
int eventMask() const;
|
||||
/// Returns the value of the eventMask passed to the constructor.
|
||||
|
||||
int scanInterval() const;
|
||||
/// Returns the scan interval in seconds.
|
||||
|
||||
const File & directory() const;
|
||||
/// Returns the directory being watched.
|
||||
|
||||
bool supportsMoveEvents() const;
|
||||
/// Returns true iff the platform supports DW_ITEM_MOVED_FROM/itemMovedFrom and
|
||||
/// DW_ITEM_MOVED_TO/itemMovedTo events.
|
||||
|
||||
protected:
|
||||
void init();
|
||||
void stop();
|
||||
void run();
|
||||
|
||||
private:
|
||||
DirectoryWatcher();
|
||||
DirectoryWatcher(const DirectoryWatcher &);
|
||||
DirectoryWatcher & operator=(const DirectoryWatcher &);
|
||||
|
||||
Thread _thread;
|
||||
File _directory;
|
||||
int _eventMask;
|
||||
AtomicCounter _eventsSuspended;
|
||||
int _scanInterval;
|
||||
DirectoryWatcherStrategy * _pStrategy;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// inlines
|
||||
//
|
||||
|
||||
|
||||
inline bool DirectoryWatcher::eventsSuspended() const
|
||||
{
|
||||
return _eventsSuspended.value() > 0;
|
||||
}
|
||||
|
||||
|
||||
inline int DirectoryWatcher::eventMask() const
|
||||
{
|
||||
return _eventMask;
|
||||
}
|
||||
|
||||
|
||||
inline int DirectoryWatcher::scanInterval() const
|
||||
{
|
||||
return _scanInterval;
|
||||
}
|
||||
|
||||
|
||||
inline const File & DirectoryWatcher::directory() const
|
||||
{
|
||||
return _directory;
|
||||
}
|
||||
|
||||
|
||||
} // namespace Poco
|
||||
|
||||
|
||||
#endif // POCO_NO_INOTIFY
|
||||
|
||||
|
||||
#endif // Foundation_DirectoryWatcher_INCLUDED
|
@ -1,602 +0,0 @@
|
||||
//
|
||||
// DirectoryWatcher.cpp
|
||||
//
|
||||
// Library: Foundation
|
||||
// Package: Filesystem
|
||||
// Module: DirectoryWatcher
|
||||
//
|
||||
// Copyright (c) 2012, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#include "Poco/DirectoryWatcher.h"
|
||||
|
||||
|
||||
#ifndef POCO_NO_INOTIFY
|
||||
|
||||
|
||||
#include "Poco/Path.h"
|
||||
#include "Poco/Glob.h"
|
||||
#include "Poco/DirectoryIterator.h"
|
||||
#include "Poco/Event.h"
|
||||
#include "Poco/Exception.h"
|
||||
#include "Poco/Buffer.h"
|
||||
#if POCO_OS == POCO_OS_LINUX || POCO_OS == POCO_OS_ANDROID
|
||||
#include <sys/inotify.h>
|
||||
#include <sys/select.h>
|
||||
#include <unistd.h>
|
||||
#elif POCO_OS == POCO_OS_MAC_OS_X || POCO_OS == POCO_OS_FREE_BSD
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/event.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#if (POCO_OS == POCO_OS_FREE_BSD) && !defined(O_EVTONLY)
|
||||
#define O_EVTONLY 0x8000
|
||||
#endif
|
||||
#endif
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <map>
|
||||
|
||||
namespace Poco {
|
||||
|
||||
|
||||
class DirectoryWatcherStrategy
|
||||
{
|
||||
public:
|
||||
DirectoryWatcherStrategy(DirectoryWatcher& owner):
|
||||
_owner(owner)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~DirectoryWatcherStrategy()
|
||||
{
|
||||
}
|
||||
|
||||
DirectoryWatcher& owner()
|
||||
{
|
||||
return _owner;
|
||||
}
|
||||
|
||||
virtual void run() = 0;
|
||||
virtual void stop() = 0;
|
||||
virtual bool supportsMoveEvents() const = 0;
|
||||
|
||||
protected:
|
||||
struct ItemInfo
|
||||
{
|
||||
ItemInfo():
|
||||
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;
|
||||
};
|
||||
typedef std::map<std::string, ItemInfo> ItemInfoMap;
|
||||
|
||||
void scan(ItemInfoMap& entries)
|
||||
{
|
||||
DirectoryIterator it(owner().directory());
|
||||
DirectoryIterator end;
|
||||
while (it != end)
|
||||
{
|
||||
entries[it.path().getFileName()] = ItemInfo(*it);
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
void compare(ItemInfoMap& oldEntries, ItemInfoMap& newEntries)
|
||||
{
|
||||
for (ItemInfoMap::iterator itn = newEntries.begin(); itn != newEntries.end(); ++itn)
|
||||
{
|
||||
ItemInfoMap::iterator ito = oldEntries.find(itn->first);
|
||||
if (ito != oldEntries.end())
|
||||
{
|
||||
if ((owner().eventMask() & DirectoryWatcher::DW_ITEM_MODIFIED) && !owner().eventsSuspended())
|
||||
{
|
||||
if (itn->second.size != ito->second.size || itn->second.lastModified != ito->second.lastModified)
|
||||
{
|
||||
Poco::File f(itn->second.path);
|
||||
DirectoryWatcher::DirectoryEvent ev(f, DirectoryWatcher::DW_ITEM_MODIFIED);
|
||||
owner().itemModified(&owner(), ev);
|
||||
}
|
||||
}
|
||||
oldEntries.erase(ito);
|
||||
}
|
||||
else if ((owner().eventMask() & DirectoryWatcher::DW_ITEM_ADDED) && !owner().eventsSuspended())
|
||||
{
|
||||
Poco::File f(itn->second.path);
|
||||
DirectoryWatcher::DirectoryEvent ev(f, DirectoryWatcher::DW_ITEM_ADDED);
|
||||
owner().itemAdded(&owner(), ev);
|
||||
}
|
||||
}
|
||||
if ((owner().eventMask() & DirectoryWatcher::DW_ITEM_REMOVED) && !owner().eventsSuspended())
|
||||
{
|
||||
for (ItemInfoMap::iterator it = oldEntries.begin(); it != oldEntries.end(); ++it)
|
||||
{
|
||||
Poco::File f(it->second.path);
|
||||
DirectoryWatcher::DirectoryEvent ev(f, DirectoryWatcher::DW_ITEM_REMOVED);
|
||||
owner().itemRemoved(&owner(), ev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
DirectoryWatcherStrategy();
|
||||
DirectoryWatcherStrategy(const DirectoryWatcherStrategy&);
|
||||
DirectoryWatcherStrategy& operator = (const DirectoryWatcherStrategy&);
|
||||
|
||||
DirectoryWatcher& _owner;
|
||||
};
|
||||
|
||||
|
||||
#if POCO_OS == POCO_OS_WINDOWS_NT
|
||||
|
||||
|
||||
class WindowsDirectoryWatcherStrategy: public DirectoryWatcherStrategy
|
||||
{
|
||||
public:
|
||||
WindowsDirectoryWatcherStrategy(DirectoryWatcher& owner):
|
||||
DirectoryWatcherStrategy(owner)
|
||||
{
|
||||
_hStopped = CreateEventW(NULL, FALSE, FALSE, NULL);
|
||||
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());
|
||||
HANDLE hChange = FindFirstChangeNotificationA(path.c_str(), FALSE, filter);
|
||||
|
||||
if (hChange == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
try
|
||||
{
|
||||
FileImpl::handleLastErrorImpl(path);
|
||||
}
|
||||
catch (Poco::Exception& exc)
|
||||
{
|
||||
owner().scanError(&owner(), exc);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
bool stopped = false;
|
||||
while (!stopped)
|
||||
{
|
||||
try
|
||||
{
|
||||
HANDLE h[2];
|
||||
h[0] = _hStopped;
|
||||
h[1] = hChange;
|
||||
switch (WaitForMultipleObjects(2, h, FALSE, INFINITE))
|
||||
{
|
||||
case WAIT_OBJECT_0:
|
||||
stopped = true;
|
||||
break;
|
||||
case WAIT_OBJECT_0 + 1:
|
||||
{
|
||||
ItemInfoMap newEntries;
|
||||
scan(newEntries);
|
||||
compare(entries, newEntries);
|
||||
std::swap(entries, newEntries);
|
||||
if (FindNextChangeNotification(hChange) == FALSE)
|
||||
{
|
||||
FileImpl::handleLastErrorImpl(path);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw SystemException("failed to wait for directory changes");
|
||||
}
|
||||
}
|
||||
catch (Poco::Exception& exc)
|
||||
{
|
||||
owner().scanError(&owner(), exc);
|
||||
}
|
||||
}
|
||||
FindCloseChangeNotification(hChange);
|
||||
}
|
||||
|
||||
void stop()
|
||||
{
|
||||
SetEvent(_hStopped);
|
||||
}
|
||||
|
||||
bool supportsMoveEvents() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
HANDLE _hStopped;
|
||||
};
|
||||
|
||||
|
||||
#elif POCO_OS == POCO_OS_LINUX || POCO_OS == POCO_OS_ANDROID
|
||||
|
||||
|
||||
class LinuxDirectoryWatcherStrategy: public DirectoryWatcherStrategy
|
||||
{
|
||||
public:
|
||||
LinuxDirectoryWatcherStrategy(DirectoryWatcher& owner):
|
||||
DirectoryWatcherStrategy(owner),
|
||||
_fd(-1),
|
||||
_stopped(false)
|
||||
{
|
||||
_fd = inotify_init();
|
||||
if (_fd == -1) throw Poco::IOException("cannot initialize inotify", errno);
|
||||
}
|
||||
|
||||
~LinuxDirectoryWatcherStrategy()
|
||||
{
|
||||
close(_fd);
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
int mask = 0;
|
||||
if (owner().eventMask() & DirectoryWatcher::DW_ITEM_ADDED)
|
||||
mask |= IN_CREATE;
|
||||
if (owner().eventMask() & DirectoryWatcher::DW_ITEM_REMOVED)
|
||||
mask |= IN_DELETE;
|
||||
if (owner().eventMask() & DirectoryWatcher::DW_ITEM_MODIFIED)
|
||||
mask |= IN_MODIFY;
|
||||
if (owner().eventMask() & DirectoryWatcher::DW_ITEM_MOVED_FROM)
|
||||
mask |= IN_MOVED_FROM;
|
||||
if (owner().eventMask() & DirectoryWatcher::DW_ITEM_MOVED_TO)
|
||||
mask |= IN_MOVED_TO;
|
||||
int wd = inotify_add_watch(_fd, owner().directory().path().c_str(), mask);
|
||||
if (wd == -1)
|
||||
{
|
||||
try
|
||||
{
|
||||
FileImpl::handleLastErrorImpl(owner().directory().path());
|
||||
}
|
||||
catch (Poco::Exception& exc)
|
||||
{
|
||||
owner().scanError(&owner(), exc);
|
||||
}
|
||||
}
|
||||
|
||||
Poco::Buffer<char> buffer(4096);
|
||||
while (!_stopped.load(std::memory_order_relaxed))
|
||||
{
|
||||
fd_set fds;
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(_fd, &fds);
|
||||
|
||||
struct timeval tv;
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 200000;
|
||||
|
||||
if (select(_fd + 1, &fds, NULL, NULL, &tv) == 1)
|
||||
{
|
||||
int n = read(_fd, buffer.begin(), buffer.size());
|
||||
int i = 0;
|
||||
if (n > 0)
|
||||
{
|
||||
while (n > 0)
|
||||
{
|
||||
struct inotify_event* event = reinterpret_cast<struct inotify_event*>(buffer.begin() + i);
|
||||
|
||||
if (event->len > 0)
|
||||
{
|
||||
if (!owner().eventsSuspended())
|
||||
{
|
||||
Poco::Path p(owner().directory().path());
|
||||
p.makeDirectory();
|
||||
p.setFileName(event->name);
|
||||
Poco::File f(p.toString());
|
||||
|
||||
if ((event->mask & IN_CREATE) && (owner().eventMask() & DirectoryWatcher::DW_ITEM_ADDED))
|
||||
{
|
||||
DirectoryWatcher::DirectoryEvent ev(f, DirectoryWatcher::DW_ITEM_ADDED);
|
||||
owner().itemAdded(&owner(), ev);
|
||||
}
|
||||
if ((event->mask & IN_DELETE) && (owner().eventMask() & DirectoryWatcher::DW_ITEM_REMOVED))
|
||||
{
|
||||
DirectoryWatcher::DirectoryEvent ev(f, DirectoryWatcher::DW_ITEM_REMOVED);
|
||||
owner().itemRemoved(&owner(), ev);
|
||||
}
|
||||
if ((event->mask & IN_MODIFY) && (owner().eventMask() & DirectoryWatcher::DW_ITEM_MODIFIED))
|
||||
{
|
||||
DirectoryWatcher::DirectoryEvent ev(f, DirectoryWatcher::DW_ITEM_MODIFIED);
|
||||
owner().itemModified(&owner(), ev);
|
||||
}
|
||||
if ((event->mask & IN_MOVED_FROM) && (owner().eventMask() & DirectoryWatcher::DW_ITEM_MOVED_FROM))
|
||||
{
|
||||
DirectoryWatcher::DirectoryEvent ev(f, DirectoryWatcher::DW_ITEM_MOVED_FROM);
|
||||
owner().itemMovedFrom(&owner(), ev);
|
||||
}
|
||||
if ((event->mask & IN_MOVED_TO) && (owner().eventMask() & DirectoryWatcher::DW_ITEM_MOVED_TO))
|
||||
{
|
||||
DirectoryWatcher::DirectoryEvent ev(f, DirectoryWatcher::DW_ITEM_MOVED_TO);
|
||||
owner().itemMovedTo(&owner(), ev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
i += sizeof(inotify_event) + event->len;
|
||||
n -= sizeof(inotify_event) + event->len;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void stop()
|
||||
{
|
||||
_stopped.store(true, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
bool supportsMoveEvents() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
int _fd;
|
||||
std::atomic<bool> _stopped;
|
||||
};
|
||||
|
||||
|
||||
#elif POCO_OS == POCO_OS_MAC_OS_X || POCO_OS == POCO_OS_FREE_BSD
|
||||
|
||||
|
||||
class BSDDirectoryWatcherStrategy: public DirectoryWatcherStrategy
|
||||
{
|
||||
public:
|
||||
BSDDirectoryWatcherStrategy(DirectoryWatcher& owner):
|
||||
DirectoryWatcherStrategy(owner),
|
||||
_queueFD(-1),
|
||||
_dirFD(-1),
|
||||
_stopped(false)
|
||||
{
|
||||
_dirFD = open(owner.directory().path().c_str(), O_EVTONLY);
|
||||
if (_dirFD < 0) throw Poco::FileNotFoundException(owner.directory().path());
|
||||
_queueFD = kqueue();
|
||||
if (_queueFD < 0)
|
||||
{
|
||||
close(_dirFD);
|
||||
throw Poco::SystemException("Cannot create kqueue", errno);
|
||||
}
|
||||
}
|
||||
|
||||
~BSDDirectoryWatcherStrategy()
|
||||
{
|
||||
close(_dirFD);
|
||||
close(_queueFD);
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
Poco::Timestamp lastScan;
|
||||
ItemInfoMap entries;
|
||||
scan(entries);
|
||||
|
||||
while (!_stopped.load(std::memory_order_relaxed))
|
||||
{
|
||||
struct timespec timeout;
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_nsec = 200000000;
|
||||
unsigned eventFilter = NOTE_WRITE;
|
||||
struct kevent event;
|
||||
struct kevent eventData;
|
||||
EV_SET(&event, _dirFD, EVFILT_VNODE, EV_ADD | EV_CLEAR, eventFilter, 0, 0);
|
||||
int nEvents = kevent(_queueFD, &event, 1, &eventData, 1, &timeout);
|
||||
if (nEvents < 0 || eventData.flags == EV_ERROR)
|
||||
{
|
||||
try
|
||||
{
|
||||
FileImpl::handleLastErrorImpl(owner().directory().path());
|
||||
}
|
||||
catch (Poco::Exception& exc)
|
||||
{
|
||||
owner().scanError(&owner(), exc);
|
||||
}
|
||||
}
|
||||
else if (nEvents > 0 || ((owner().eventMask() & DirectoryWatcher::DW_ITEM_MODIFIED) && lastScan.isElapsed(owner().scanInterval()*1000000)))
|
||||
{
|
||||
ItemInfoMap newEntries;
|
||||
scan(newEntries);
|
||||
compare(entries, newEntries);
|
||||
std::swap(entries, newEntries);
|
||||
lastScan.update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void stop()
|
||||
{
|
||||
_stopped.store(true, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
bool supportsMoveEvents() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
int _queueFD;
|
||||
int _dirFD;
|
||||
std::atomic<bool> _stopped;
|
||||
};
|
||||
|
||||
|
||||
#else
|
||||
|
||||
|
||||
class PollingDirectoryWatcherStrategy: public DirectoryWatcherStrategy
|
||||
{
|
||||
public:
|
||||
PollingDirectoryWatcherStrategy(DirectoryWatcher& owner):
|
||||
DirectoryWatcherStrategy(owner)
|
||||
{
|
||||
}
|
||||
|
||||
~PollingDirectoryWatcherStrategy()
|
||||
{
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
ItemInfoMap entries;
|
||||
scan(entries);
|
||||
while (!_stopped.tryWait(1000*owner().scanInterval()))
|
||||
{
|
||||
try
|
||||
{
|
||||
ItemInfoMap newEntries;
|
||||
scan(newEntries);
|
||||
compare(entries, newEntries);
|
||||
std::swap(entries, newEntries);
|
||||
}
|
||||
catch (Poco::Exception& exc)
|
||||
{
|
||||
owner().scanError(&owner(), exc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void stop()
|
||||
{
|
||||
_stopped.set();
|
||||
}
|
||||
|
||||
bool supportsMoveEvents() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
Poco::Event _stopped;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
DirectoryWatcher::DirectoryWatcher(const std::string& path, int eventMask, int scanInterval):
|
||||
_directory(path),
|
||||
_eventMask(eventMask),
|
||||
_scanInterval(scanInterval)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
|
||||
DirectoryWatcher::DirectoryWatcher(const Poco::File& directory, int eventMask, int scanInterval):
|
||||
_directory(directory),
|
||||
_eventMask(eventMask),
|
||||
_scanInterval(scanInterval)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
|
||||
DirectoryWatcher::~DirectoryWatcher()
|
||||
{
|
||||
try
|
||||
{
|
||||
stop();
|
||||
delete _pStrategy;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
poco_unexpected();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DirectoryWatcher::suspendEvents()
|
||||
{
|
||||
poco_assert (_eventsSuspended > 0);
|
||||
|
||||
_eventsSuspended--;
|
||||
}
|
||||
|
||||
|
||||
void DirectoryWatcher::resumeEvents()
|
||||
{
|
||||
_eventsSuspended++;
|
||||
}
|
||||
|
||||
|
||||
void DirectoryWatcher::init()
|
||||
{
|
||||
if (!_directory.exists())
|
||||
throw Poco::FileNotFoundException(_directory.path());
|
||||
|
||||
if (!_directory.isDirectory())
|
||||
throw Poco::InvalidArgumentException("not a directory", _directory.path());
|
||||
|
||||
#if POCO_OS == POCO_OS_WINDOWS_NT
|
||||
_pStrategy = new WindowsDirectoryWatcherStrategy(*this);
|
||||
#elif POCO_OS == POCO_OS_LINUX || POCO_OS == POCO_OS_ANDROID
|
||||
_pStrategy = new LinuxDirectoryWatcherStrategy(*this);
|
||||
#elif POCO_OS == POCO_OS_MAC_OS_X || POCO_OS == POCO_OS_FREE_BSD
|
||||
_pStrategy = new BSDDirectoryWatcherStrategy(*this);
|
||||
#else
|
||||
_pStrategy = new PollingDirectoryWatcherStrategy(*this);
|
||||
#endif
|
||||
_thread.start(*this);
|
||||
}
|
||||
|
||||
|
||||
void DirectoryWatcher::run()
|
||||
{
|
||||
_pStrategy->run();
|
||||
}
|
||||
|
||||
|
||||
void DirectoryWatcher::stop()
|
||||
{
|
||||
_pStrategy->stop();
|
||||
_thread.join();
|
||||
}
|
||||
|
||||
|
||||
bool DirectoryWatcher::supportsMoveEvents() const
|
||||
{
|
||||
return _pStrategy->supportsMoveEvents();
|
||||
}
|
||||
|
||||
|
||||
} // namespace Poco
|
||||
|
||||
|
||||
#endif // POCO_NO_INOTIFY
|
@ -7,7 +7,7 @@
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <unistd.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/poll.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
@ -27,11 +27,8 @@ void trim(String & s)
|
||||
/// Allows delaying the start of query execution until the entirety of query is inserted.
|
||||
bool hasInputData()
|
||||
{
|
||||
timeval timeout = {0, 0};
|
||||
fd_set fds{};
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(STDIN_FILENO, &fds);
|
||||
return select(1, &fds, nullptr, nullptr, &timeout) == 1;
|
||||
pollfd fd{STDIN_FILENO, POLLIN, 0};
|
||||
return poll(&fd, 1, 0) == 1;
|
||||
}
|
||||
|
||||
struct NoCaseCompare
|
||||
|
@ -249,24 +249,6 @@ void ReadBufferFromFileDescriptor::rewind()
|
||||
file_offset_of_buffer_end = 0;
|
||||
}
|
||||
|
||||
|
||||
/// Assuming file descriptor supports 'select', check that we have data to read or wait until timeout.
|
||||
bool ReadBufferFromFileDescriptor::poll(size_t timeout_microseconds) const
|
||||
{
|
||||
fd_set fds;
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(fd, &fds);
|
||||
timeval timeout = { time_t(timeout_microseconds / 1000000), suseconds_t(timeout_microseconds % 1000000) };
|
||||
|
||||
int res = select(1, &fds, nullptr, nullptr, &timeout);
|
||||
|
||||
if (-1 == res)
|
||||
throwFromErrno("Cannot select", ErrorCodes::CANNOT_SELECT);
|
||||
|
||||
return res > 0;
|
||||
}
|
||||
|
||||
|
||||
size_t ReadBufferFromFileDescriptor::getFileSize()
|
||||
{
|
||||
return getSizeFromFileDescriptor(fd, getFileName());
|
||||
|
@ -75,10 +75,6 @@ public:
|
||||
|
||||
size_t readBigAt(char * to, size_t n, size_t offset, const std::function<bool(size_t)> &) override;
|
||||
bool supportsReadAt() override { return use_pread; }
|
||||
|
||||
private:
|
||||
/// Assuming file descriptor supports 'select', check that we have data to read or wait until timeout.
|
||||
bool poll(size_t timeout_microseconds) const;
|
||||
};
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user