#include #include #include #include #include #include #include #include #include #include namespace DB { namespace ErrorCodes { extern const int UNFINISHED; } void EmbeddedDictionaries::handleException(const bool throw_on_error) const { const auto exception_ptr = std::current_exception(); tryLogCurrentException(log, "Cannot load dictionary! You must resolve this manually."); if (throw_on_error) std::rethrow_exception(exception_ptr); } template bool EmbeddedDictionaries::reloadDictionary(MultiVersion & dictionary, const bool throw_on_error, const bool force_reload) { const auto & config = context.getConfigRef(); bool defined_in_config = Dictionary::isConfigured(config); bool not_initialized = dictionary.get() == nullptr; if (defined_in_config && (force_reload || !is_fast_start_stage || not_initialized)) { try { auto new_dictionary = std::make_unique(); new_dictionary->reload(config); dictionary.set(new_dictionary.release()); } catch (...) { handleException(throw_on_error); return false; } } return true; } bool EmbeddedDictionaries::reloadImpl(const bool throw_on_error, const bool force_reload) { std::unique_lock lock(mutex); /** If you can not update the directories, then despite this, do not throw an exception (use the old directories). * If there are no old correct directories, then when using functions that depend on them, * will throw an exception. * An attempt is made to load each directory separately. */ LOG_INFO(log, "Loading dictionaries."); bool was_exception = false; #if USE_MYSQL if (!reloadDictionary(tech_data_hierarchy, throw_on_error, force_reload)) was_exception = true; #endif if (!reloadDictionary(regions_hierarchies, throw_on_error, force_reload)) was_exception = true; if (!reloadDictionary(regions_names, throw_on_error, force_reload)) was_exception = true; if (!was_exception) LOG_INFO(log, "Loaded dictionaries."); return !was_exception; } void EmbeddedDictionaries::reloadPeriodically() { setThreadName("DictReload"); while (true) { if (destroy.tryWait(cur_reload_period * 1000)) return; if (reloadImpl(false)) { /// Success cur_reload_period = reload_period; is_fast_start_stage = false; } if (is_fast_start_stage) { cur_reload_period = std::min(reload_period, 2 * cur_reload_period); /// exponentially increase delay is_fast_start_stage = cur_reload_period < reload_period; /// leave fast start state } } } EmbeddedDictionaries::EmbeddedDictionaries(Context & context_, const bool throw_on_error) : log(&Logger::get("EmbeddedDictionaries")) , context(context_) , reload_period(context_.getConfigRef().getInt("builtin_dictionaries_reload_interval", 3600)) { reloadImpl(throw_on_error); reloading_thread = std::thread([this] { reloadPeriodically(); }); } EmbeddedDictionaries::~EmbeddedDictionaries() { destroy.set(); reloading_thread.join(); } void EmbeddedDictionaries::reload() { if (!reloadImpl(true, true)) throw Exception("Some embedded dictionaries were not successfully reloaded", ErrorCodes::UNFINISHED); } }