From 0c89775b052d1698e819d391309112443b0d3866 Mon Sep 17 00:00:00 2001 From: Michael Carlberg <c@rlberg.se> Date: Tue, 21 Jun 2016 04:34:11 +0200 Subject: [PATCH] feat: Throttle inotify event polling --- include/modules/base.hpp | 62 ++++++++++++++++++++++++++-------------- 1 file changed, 40 insertions(+), 22 deletions(-) diff --git a/include/modules/base.hpp b/include/modules/base.hpp index a1e3f79d..734db44a 100644 --- a/include/modules/base.hpp +++ b/include/modules/base.hpp @@ -27,6 +27,8 @@ using namespace std::chrono_literals; #define Stringify(expr) _Stringify(expr) #define DefineModule(ModuleName, ModuleType) struct ModuleName : public ModuleType<ModuleName> +#define DefineModule2(ModuleName, ModuleType, P2) struct ModuleName : public ModuleType<ModuleName, P2> +#define DefineModule3(ModuleName, ModuleType, P2, P3) struct ModuleName : public ModuleType<ModuleName, P2, P3> #define CastModule(ModuleName) static_cast<ModuleName *>(this) #define ConstCastModule(ModuleName) static_cast<ModuleName const &>(*this) @@ -83,7 +85,7 @@ namespace modules virtual bool handle_command(std::string cmd) = 0; }; - template<typename ModuleImpl> + template<class ModuleImpl> class Module : public ModuleInterface { concurrency::Atomic<bool> enabled_flag; @@ -240,7 +242,7 @@ namespace modules } }; - template<typename ModuleImpl> + template<class ModuleImpl> class StaticModule : public Module<ModuleImpl> { using Module<ModuleImpl>::Module; @@ -258,7 +260,7 @@ namespace modules } }; - template<typename ModuleImpl> + template<class ModuleImpl> class TimerModule : public Module<ModuleImpl> { protected: @@ -287,7 +289,7 @@ namespace modules } }; - template<typename ModuleImpl> + template<class ModuleImpl> class EventModule : public Module<ModuleImpl> { using Module<ModuleImpl>::Module; @@ -320,39 +322,39 @@ namespace modules } }; - template<typename ModuleImpl> + template<class ModuleImpl, const int ThrottleLimit = 2, const int ThrottleWindowMs = 50> class InotifyModule : public Module<ModuleImpl> { - using Module<ModuleImpl>::Module; - protected: - std::map<std::string, int> watch_list; + concurrency::SpinLock poll_lock; - concurrency::SpinLock update_lock; + std::unique_ptr<EventThrottler> poll_throttler; + + std::map<std::string, int> watch_list; void runner() { // warmup - if (CastModule(ModuleImpl)->on_event(nullptr)) - CastModule(ModuleImpl)->broadcast(); + CastModule(ModuleImpl)->on_event(nullptr); + CastModule(ModuleImpl)->broadcast(); while (this->enabled()) { try { - this->poll_events(); + std::lock_guard<concurrency::SpinLock> lck(this->poll_lock); + if (this->poll_throttler->passthrough()) + this->poll_events(); } catch (InotifyException &e) { get_logger()->fatal(e.what()); } } } - void idle() const - { - // std::this_thread::sleep_for(1s); + void idle() const { + // this->sleep(1s); } void poll_events() { - std::lock_guard<concurrency::SpinLock> lck(this->update_lock); std::vector<std::unique_ptr<InotifyWatch>> watches; try { @@ -360,8 +362,8 @@ namespace modules watches.emplace_back(std::make_unique<InotifyWatch>(w.first, w.second)); } catch (InotifyException &e) { watches.clear(); - get_logger()->error(e.what()); - std::this_thread::sleep_for(100ms); + log_error(e.what()); + this->sleep(0.1s); return; } @@ -376,6 +378,11 @@ namespace modules watches.clear(); + std::lock_guard<concurrency::SpinLock> lck(this->update_lock); + + if (!this->poll_throttler->passthrough()) + return; + if (CastModule(ModuleImpl)->on_event(event.get())) CastModule(ModuleImpl)->broadcast(); @@ -385,24 +392,35 @@ namespace modules } } - void watch(const std::string& path, int mask = InotifyEvent::ALL) + void watch(std::string path, int mask = InotifyEvent::ALL) { log_trace(path); this->watch_list.insert(std::make_pair(path, mask)); } public: - InotifyModule(const std::string& name, const std::string& path, int mask = InotifyEvent::ALL) : Module<ModuleImpl>(name) - { + InotifyModule(std::string name) + : Module<ModuleImpl>(name) + , poll_throttler(std::make_unique<EventThrottler>(event_throttler::limit_t(ThrottleLimit), event_throttler::timewindow_t(ThrottleWindowMs))) {} + + InotifyModule(std::string name, std::string path, int mask = InotifyEvent::ALL) + : Module<ModuleImpl>(name) + , poll_throttler(std::make_unique<EventThrottler>(event_throttler::limit_t(ThrottleLimit), event_throttler::timewindow_t(ThrottleWindowMs))) { this->watch(path, mask); } - InotifyModule(const std::string& name, std::vector<std::string> paths, int mask = InotifyEvent::ALL) : Module<ModuleImpl>(name) + InotifyModule(std::string name, std::vector<std::string> paths, int mask = InotifyEvent::ALL) + : Module<ModuleImpl>(name) + , poll_throttler(std::make_unique<EventThrottler>(event_throttler::limit_t(ThrottleLimit), event_throttler::timewindow_t(ThrottleWindowMs))) { for (auto &&path : paths) this->watch(path, mask); } + ~InotifyModule() { + std::lock_guard<concurrency::SpinLock> lck(this->poll_lock); + } + void start() { this->enable(true);