From 9fc42dac53d163546403f0164706f6709928af07 Mon Sep 17 00:00:00 2001 From: sowle Date: Tue, 2 Jul 2019 18:38:35 +0300 Subject: [PATCH] daemon: checking for free space (--disable-stop-on-low-free-space was also added) + minor refactoring on critical errors handling --- src/common/command_line.cpp | 1 + src/common/command_line.h | 1 + src/currency_core/currency_core.cpp | 18 +++++- src/currency_core/currency_core.h | 9 ++- .../currency_protocol_handler.inl | 8 +-- .../currency_protocol_handler_common.h | 8 ++- src/daemon/daemon.cpp | 59 +++++++++++++++++-- src/daemon/daemon_commands_handler.h | 5 +- 8 files changed, 87 insertions(+), 22 deletions(-) diff --git a/src/common/command_line.cpp b/src/common/command_line.cpp index 0aefbc17..c1fd2646 100644 --- a/src/common/command_line.cpp +++ b/src/common/command_line.cpp @@ -28,4 +28,5 @@ namespace command_line const arg_descriptor arg_disable_upnp = { "disable-upnp", "Disable UPnP (enhances local network privacy)", false, true }; const arg_descriptor arg_disable_stop_if_time_out_of_sync = { "disable-stop-if-time-out-of-sync", "Do not stop the daemon if serious time synchronization problem is detected", false, true }; + const arg_descriptor arg_disable_stop_on_low_free_space = { "disable-stop-on-low-free-space", "Do not stop the daemon if free space at data dir is critically low", false, true }; } diff --git a/src/common/command_line.h b/src/common/command_line.h index 2dff6a3d..1f14ef22 100644 --- a/src/common/command_line.h +++ b/src/common/command_line.h @@ -186,4 +186,5 @@ namespace command_line extern const arg_descriptor arg_show_rpc_autodoc; extern const arg_descriptor arg_disable_upnp; extern const arg_descriptor arg_disable_stop_if_time_out_of_sync; + extern const arg_descriptor arg_disable_stop_on_low_free_space; } diff --git a/src/currency_core/currency_core.cpp b/src/currency_core/currency_core.cpp index 24473ff0..8d621854 100644 --- a/src/currency_core/currency_core.cpp +++ b/src/currency_core/currency_core.cpp @@ -33,7 +33,7 @@ namespace currency m_miner(this, m_blockchain_storage), m_miner_address(boost::value_initialized()), m_starter_message_showed(false), - m_stop_handler(nullptr) + m_critical_error_handler(nullptr) { set_currency_protocol(pprotocol); } @@ -48,9 +48,9 @@ namespace currency m_mempool.set_protocol(m_pprotocol); } //----------------------------------------------------------------------------------- - void core::set_stop_handler(i_stop_handler *handler) + void core::set_critical_error_handler(i_critical_error_handler* handler) { - m_stop_handler = handler; + m_critical_error_handler = handler; } //----------------------------------------------------------------------------------- bool core::set_checkpoints(checkpoints&& chk_pts) @@ -685,6 +685,7 @@ namespace currency } m_prune_alt_blocks_interval.do_call([this](){return m_blockchain_storage.prune_aged_alt_blocks();}); + m_check_free_space_interval.do_call([this](){ check_free_space(); return true; }); m_miner.on_idle(); m_mempool.on_idle(); return true; @@ -709,6 +710,17 @@ namespace currency l->on_blockchain_update(); } //----------------------------------------------------------------------------------------------- +#define MINIMUM_REQUIRED_FREE_SPACE_BYTES (1024 * 1024 * 100) + void core::check_free_space() + { + boost::filesystem::space_info si = boost::filesystem::space(m_config_folder); + + if (si.available < MINIMUM_REQUIRED_FREE_SPACE_BYTES) + { + m_critical_error_handler->on_critical_low_free_space(si.available, MINIMUM_REQUIRED_FREE_SPACE_BYTES); + } + } + //----------------------------------------------------------------------------------------------- } #undef LOG_DEFAULT_CHANNEL diff --git a/src/currency_core/currency_core.h b/src/currency_core/currency_core.h index b27b07fb..2f7f7485 100644 --- a/src/currency_core/currency_core.h +++ b/src/currency_core/currency_core.h @@ -81,8 +81,8 @@ namespace currency size_t get_alternative_blocks_count(); void set_currency_protocol(i_currency_protocol* pprotocol); - void set_stop_handler(i_stop_handler *handler); - i_stop_handler* get_stop_handler() const { return m_stop_handler; } + void set_critical_error_handler(i_critical_error_handler *handler); + i_critical_error_handler* get_critical_error_handler() const { return m_critical_error_handler; } bool set_checkpoints(checkpoints&& chk_pts); bool get_pool_transactions(std::list& txs); @@ -136,17 +136,20 @@ namespace currency void notify_blockchain_update_listeners(); + void check_free_space(); + blockchain_storage m_blockchain_storage; tx_memory_pool m_mempool; i_currency_protocol* m_pprotocol; - i_stop_handler* m_stop_handler; + i_critical_error_handler* m_critical_error_handler; critical_section m_incoming_tx_lock; miner m_miner; account_public_address m_miner_address; std::string m_config_folder; currency_protocol_stub m_protocol_stub; math_helper::once_a_time_seconds<60*60*12, false> m_prune_alt_blocks_interval; + math_helper::once_a_time_seconds<60, true> m_check_free_space_interval; friend class tx_validate_inputs; std::atomic m_starter_message_showed; diff --git a/src/currency_protocol/currency_protocol_handler.inl b/src/currency_protocol/currency_protocol_handler.inl index 2f3225a1..d1c482e0 100644 --- a/src/currency_protocol/currency_protocol_handler.inl +++ b/src/currency_protocol/currency_protocol_handler.inl @@ -131,12 +131,10 @@ namespace currency if (!add_time_delta_and_check_time_sync(context.m_time_delta)) { // serious time sync problem detected - i_stop_handler* ish(m_core.get_stop_handler()); - if (ish != nullptr) + i_critical_error_handler* ceh(m_core.get_critical_error_handler()); + if (ceh != nullptr && ceh->on_critical_time_sync_error()) { - // this is daemon -- stop immediately - ish->stop_handling(); - LOG_ERROR(ENDL << ENDL << "Serious time sync problem detected, daemon will stop immediately" << ENDL << ENDL); + // error is handled by a callee, should not be ignored here, stop processing immideately return true; } } diff --git a/src/currency_protocol/currency_protocol_handler_common.h b/src/currency_protocol/currency_protocol_handler_common.h index 3a71f4dd..1d965695 100644 --- a/src/currency_protocol/currency_protocol_handler_common.h +++ b/src/currency_protocol/currency_protocol_handler_common.h @@ -40,9 +40,13 @@ namespace currency /************************************************************************/ /* */ /************************************************************************/ - struct i_stop_handler + struct i_critical_error_handler { - virtual void stop_handling() = 0; + // called by currency protocol when the time is critically out of sync + // return true if the error is not ignored and the called should not proceed + virtual bool on_critical_time_sync_error() = 0; + + virtual bool on_critical_low_free_space(uint64_t available, uint64_t required) = 0; }; diff --git a/src/daemon/daemon.cpp b/src/daemon/daemon.cpp index 511b6441..65b58cb1 100644 --- a/src/daemon/daemon.cpp +++ b/src/daemon/daemon.cpp @@ -43,6 +43,49 @@ namespace po = boost::program_options; bool command_line_preprocessor(const boost::program_options::variables_map& vm); +template +struct core_critical_error_handler_t : public currency::i_critical_error_handler +{ + core_critical_error_handler_t(daemon_commands_handler& dch, p2psrv_t& p2psrv, bool dont_stop_on_time_error, bool dont_stop_on_low_space) + : dch(dch) + , p2psrv(p2psrv) + , dont_stop_on_time_error(dont_stop_on_time_error) + , dont_stop_on_low_space(dont_stop_on_low_space) + {} + + // interface currency::i_critical_error_handler + virtual bool on_critical_time_sync_error() override + { + if (dont_stop_on_time_error) + return false; // ignore such errors + + LOG_ERROR(ENDL << ENDL << "Serious time sync problem detected, daemon will stop immediately" << ENDL << ENDL); + + // stop handling + dch.stop_handling(); + return true; // the caller must stop processing + } + + // interface currency::i_critical_error_handler + virtual bool on_critical_low_free_space(uint64_t available, uint64_t required) override + { + if (dont_stop_on_low_space) + return false; // ignore such errors + + LOG_ERROR(ENDL << ENDL << "Free space at data directory is critically low (" << available / (1024 * 1024) << " MB, while " << required / (1024 * 1024) << " MB is required), daemon will stop immediately" << ENDL << ENDL); + + // stop handling + dch.stop_handling(); + p2psrv.send_stop_signal(); + return true; // the caller must stop processing + } + + daemon_commands_handler& dch; + p2psrv_t& p2psrv; + bool dont_stop_on_time_error; + bool dont_stop_on_low_space; +}; + int main(int argc, char* argv[]) { try @@ -82,6 +125,7 @@ int main(int argc, char* argv[]) command_line::add_arg(desc_cmd_sett, command_line::arg_show_details); command_line::add_arg(desc_cmd_sett, command_line::arg_show_rpc_autodoc); command_line::add_arg(desc_cmd_sett, command_line::arg_disable_stop_if_time_out_of_sync); + command_line::add_arg(desc_cmd_sett, command_line::arg_disable_stop_on_low_free_space); arg_market_disable.default_value = true; @@ -89,7 +133,8 @@ int main(int argc, char* argv[]) currency::core::init_options(desc_cmd_sett); currency::core_rpc_server::init_options(desc_cmd_sett); - nodetool::node_server >::init_options(desc_cmd_sett); + typedef nodetool::node_server > p2psrv_t; + p2psrv_t::init_options(desc_cmd_sett); currency::miner::init_options(desc_cmd_sett); bc_services::bc_offers_service::init_options(desc_cmd_sett); currency::stratum_server::init_options(desc_cmd_sett); @@ -163,14 +208,16 @@ int main(int argc, char* argv[]) offers_service.set_disabled(true); currency::core ccore(NULL); currency::t_currency_protocol_handler cprotocol(ccore, NULL ); - nodetool::node_server > p2psrv(cprotocol); + p2psrv_t p2psrv(cprotocol); currency::core_rpc_server rpc_server(ccore, p2psrv, offers_service); cprotocol.set_p2p_endpoint(&p2psrv); ccore.set_currency_protocol(&cprotocol); daemon_commands_handler dch(p2psrv, rpc_server); - - if (!command_line::get_arg(vm, command_line::arg_disable_stop_if_time_out_of_sync)) - ccore.set_stop_handler(&dch); + + core_critical_error_handler_t cceh(dch, p2psrv, + command_line::get_arg(vm, command_line::arg_disable_stop_if_time_out_of_sync), + command_line::get_arg(vm, command_line::arg_disable_stop_on_low_free_space)); + ccore.set_critical_error_handler(&cceh); //ccore.get_blockchain_storage().get_attachment_services_manager().add_service(&offers_service); std::shared_ptr stratum_server_ptr; @@ -309,7 +356,7 @@ int main(int argc, char* argv[]) LOG_PRINT_L0("Deinitializing p2p..."); p2psrv.deinit(); - ccore.set_stop_handler(nullptr); + ccore.set_critical_error_handler(nullptr); ccore.set_currency_protocol(NULL); cprotocol.set_p2p_endpoint(NULL); diff --git a/src/daemon/daemon_commands_handler.h b/src/daemon/daemon_commands_handler.h index ab3f5698..e5f7fcc2 100644 --- a/src/daemon/daemon_commands_handler.h +++ b/src/daemon/daemon_commands_handler.h @@ -20,7 +20,7 @@ PUSH_WARNINGS DISABLE_VS_WARNINGS(4100) -class daemon_commands_handler : public currency::i_stop_handler +class daemon_commands_handler { typedef nodetool::node_server > srv_type; srv_type& m_srv; @@ -75,8 +75,7 @@ public: return true; } - // interface currency::i_stop_handler - virtual void stop_handling() override + void stop_handling() { m_cmd_binder.stop_handling(); }