ClickHouse/src/Storages/FileLog/DirectoryWatcherBase.cpp

141 lines
4.8 KiB
C++
Raw Normal View History

2021-10-10 16:31:32 +00:00
#include <Interpreters/Context.h>
#include <Storages/FileLog/DirectoryWatcherBase.h>
#include <Storages/FileLog/FileLogDirectoryWatcher.h>
#include <filesystem>
#include <unistd.h>
#include <sys/inotify.h>
#include <sys/select.h>
namespace DB
{
namespace ErrorCodes
{
extern const int FILE_DOESNT_EXIST;
extern const int DIRECTORY_DOESNT_EXIST;
2021-10-11 04:06:31 +00:00
extern const int IO_SETUP_ERROR;
2021-10-10 16:31:32 +00:00
}
2021-10-11 04:06:31 +00:00
static constexpr int event_size = sizeof(struct inotify_event);
static constexpr int buffer_size = 1024 * (NAME_MAX + event_size + 1);
DirectoryWatcherBase::DirectoryWatcherBase(
FileLogDirectoryWatcher & owner_, const std::string & path_, ContextPtr context_, int event_mask_)
: WithContext(context_->getGlobalContext()), owner(owner_), path(path_), event_mask(event_mask_)
2021-10-10 16:31:32 +00:00
{
if (!std::filesystem::exists(path))
throw Exception(ErrorCodes::FILE_DOESNT_EXIST, "The path {} does not exist.", path);
if (!std::filesystem::is_directory(path))
throw Exception(ErrorCodes::DIRECTORY_DOESNT_EXIST, "The path {} does not a directory.", path);
fd = inotify_init();
if (fd == -1)
2021-10-11 04:06:31 +00:00
throw Exception("cannot initialize inotify", ErrorCodes::IO_SETUP_ERROR);
2021-10-10 16:31:32 +00:00
watch_task = getContext()->getMessageBrokerSchedulePool().createTask("directory_watch", [this] { watchFunc(); });
start();
}
void DirectoryWatcherBase::watchFunc()
{
int mask = 0;
if (eventMask() & DirectoryWatcherBase::DW_ITEM_ADDED)
mask |= IN_CREATE;
if (eventMask() & DirectoryWatcherBase::DW_ITEM_REMOVED)
mask |= IN_DELETE;
if (eventMask() & DirectoryWatcherBase::DW_ITEM_MODIFIED)
mask |= IN_MODIFY;
if (eventMask() & DirectoryWatcherBase::DW_ITEM_MOVED_FROM)
mask |= IN_MOVED_FROM;
if (eventMask() & DirectoryWatcherBase::DW_ITEM_MOVED_TO)
mask |= IN_MOVED_TO;
int wd = inotify_add_watch(fd, path.c_str(), mask);
if (wd == -1)
{
2021-10-11 04:06:31 +00:00
owner.onError(Exception(ErrorCodes::IO_SETUP_ERROR, "Watch directory {} failed.", path));
2021-10-10 16:31:32 +00:00
}
std::string buffer;
2021-10-11 04:06:31 +00:00
buffer.resize(buffer_size);
2021-10-10 16:31:32 +00:00
fd_set fds;
2021-10-11 04:06:31 +00:00
while (!stopped)
2021-10-10 16:31:32 +00:00
{
FD_ZERO(&fds);
FD_SET(fd, &fds);
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 200000;
if (select(fd + 1, &fds, nullptr, nullptr, &tv) == 1)
{
int n = read(fd, buffer.data(), buffer.size());
int i = 0;
if (n > 0)
{
while (n > 0)
{
struct inotify_event * p_event = reinterpret_cast<struct inotify_event *>(buffer.data() + i);
if (p_event->len > 0)
{
if ((p_event->mask & IN_CREATE) && (eventMask() & DirectoryWatcherBase::DW_ITEM_ADDED))
{
DirectoryWatcherBase::DirectoryEvent ev(p_event->name, DirectoryWatcherBase::DW_ITEM_ADDED);
owner.onItemAdded(ev);
}
if ((p_event->mask & IN_DELETE) && (eventMask() & DirectoryWatcherBase::DW_ITEM_REMOVED))
{
DirectoryWatcherBase::DirectoryEvent ev(p_event->name, DirectoryWatcherBase::DW_ITEM_REMOVED);
owner.onItemRemoved(ev);
}
if ((p_event->mask & IN_MODIFY) && (eventMask() & DirectoryWatcherBase::DW_ITEM_MODIFIED))
{
DirectoryWatcherBase::DirectoryEvent ev(p_event->name, DirectoryWatcherBase::DW_ITEM_MODIFIED);
owner.onItemModified(ev);
}
if ((p_event->mask & IN_MOVED_FROM) && (eventMask() & DirectoryWatcherBase::DW_ITEM_MOVED_FROM))
{
DirectoryWatcherBase::DirectoryEvent ev(p_event->name, DirectoryWatcherBase::DW_ITEM_MOVED_FROM);
owner.onItemMovedFrom(ev);
}
if ((p_event->mask & IN_MOVED_TO) && (eventMask() & DirectoryWatcherBase::DW_ITEM_MOVED_TO))
{
DirectoryWatcherBase::DirectoryEvent ev(p_event->name, DirectoryWatcherBase::DW_ITEM_MOVED_TO);
owner.onItemMovedTo(ev);
}
}
i += sizeof(inotify_event) + p_event->len;
n -= sizeof(inotify_event) + p_event->len;
}
}
}
}
}
DirectoryWatcherBase::~DirectoryWatcherBase()
{
stop();
close(fd);
}
void DirectoryWatcherBase::start()
{
if (watch_task)
watch_task->activateAndSchedule();
}
void DirectoryWatcherBase::stop()
{
2021-10-11 04:06:31 +00:00
stopped = true;
2021-10-10 16:31:32 +00:00
if (watch_task)
watch_task->deactivate();
}
}