2016-10-11 14:37:27 +00:00
|
|
|
#include "ConfigReloader.h"
|
2016-01-17 13:34:36 +00:00
|
|
|
|
|
|
|
#include <Poco/Util/Application.h>
|
|
|
|
#include <Poco/File.h>
|
|
|
|
|
|
|
|
#include <common/logger_useful.h>
|
|
|
|
|
2017-04-01 09:19:00 +00:00
|
|
|
#include <Interpreters/Context.h>
|
|
|
|
#include <Common/setThreadName.h>
|
|
|
|
#include <Common/ConfigProcessor.h>
|
2016-01-17 13:34:36 +00:00
|
|
|
|
|
|
|
|
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
|
2016-10-16 20:01:38 +00:00
|
|
|
constexpr decltype(ConfigReloader::reload_interval) ConfigReloader::reload_interval;
|
|
|
|
|
2017-03-17 00:44:00 +00:00
|
|
|
ConfigReloader::ConfigReloader(
|
2017-04-01 07:20:54 +00:00
|
|
|
const std::string & path_,
|
|
|
|
const std::string & include_from_path_,
|
|
|
|
zkutil::ZooKeeperNodeCache && zk_node_cache_,
|
|
|
|
Updater && updater_,
|
|
|
|
bool already_loaded)
|
|
|
|
: path(path_), include_from_path(include_from_path_)
|
|
|
|
, zk_node_cache(std::move(zk_node_cache_))
|
|
|
|
, updater(std::move(updater_))
|
2016-01-17 13:34:36 +00:00
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
if (!already_loaded)
|
|
|
|
reloadIfNewer(/* force = */ true, /* throw_on_error = */ true, /* fallback_to_preprocessed = */ true);
|
2016-10-10 08:44:52 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
thread = std::thread(&ConfigReloader::run, this);
|
2016-01-17 13:34:36 +00:00
|
|
|
}
|
|
|
|
|
2017-03-17 00:44:00 +00:00
|
|
|
|
2016-10-11 14:37:27 +00:00
|
|
|
ConfigReloader::~ConfigReloader()
|
2016-01-17 13:34:36 +00:00
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
try
|
|
|
|
{
|
|
|
|
quit = true;
|
|
|
|
zk_node_cache.getChangedEvent().set();
|
|
|
|
thread.join();
|
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
|
|
|
DB::tryLogCurrentException(__PRETTY_FUNCTION__);
|
|
|
|
}
|
2016-01-17 13:34:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-10-11 14:37:27 +00:00
|
|
|
void ConfigReloader::run()
|
2016-01-17 13:34:36 +00:00
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
setThreadName("ConfigReloader");
|
2016-01-17 13:34:36 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
while (true)
|
|
|
|
{
|
|
|
|
bool zk_changed = zk_node_cache.getChangedEvent().tryWait(std::chrono::milliseconds(reload_interval).count());
|
|
|
|
if (quit)
|
|
|
|
return;
|
2016-10-23 10:52:32 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
reloadIfNewer(zk_changed, /* throw_on_error = */ false, /* fallback_to_preprocessed = */ false);
|
|
|
|
}
|
2016-01-17 13:34:36 +00:00
|
|
|
}
|
|
|
|
|
2017-03-17 00:44:00 +00:00
|
|
|
void ConfigReloader::reloadIfNewer(bool force, bool throw_on_error, bool fallback_to_preprocessed)
|
2016-01-17 13:34:36 +00:00
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
FilesChangesTracker new_files = getNewFileList();
|
|
|
|
if (force || new_files.isDifferOrNewerThan(files))
|
|
|
|
{
|
2017-11-21 16:54:25 +00:00
|
|
|
ConfigProcessor config_processor(path);
|
2017-04-01 07:20:54 +00:00
|
|
|
ConfigProcessor::LoadedConfig loaded_config;
|
|
|
|
try
|
|
|
|
{
|
|
|
|
LOG_DEBUG(log, "Loading config `" << path << "'");
|
|
|
|
|
2017-11-21 16:54:25 +00:00
|
|
|
loaded_config = config_processor.loadConfig(/* allow_zk_includes = */ true);
|
2017-04-01 07:20:54 +00:00
|
|
|
if (loaded_config.has_zk_includes)
|
2017-11-21 16:54:25 +00:00
|
|
|
loaded_config = config_processor.loadConfigWithZooKeeperIncludes(
|
2017-04-01 07:20:54 +00:00
|
|
|
path, zk_node_cache, fallback_to_preprocessed);
|
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
|
|
|
if (throw_on_error)
|
|
|
|
throw;
|
|
|
|
|
|
|
|
tryLogCurrentException(log, "Error loading config from `" + path + "'");
|
|
|
|
return;
|
|
|
|
}
|
2017-11-21 16:54:25 +00:00
|
|
|
config_processor.savePreprocessedConfig(loaded_config);
|
2017-04-01 07:20:54 +00:00
|
|
|
|
|
|
|
/** We should remember last modification time if and only if config was sucessfully loaded
|
|
|
|
* Otherwise a race condition could occur during config files update:
|
|
|
|
* File is contain raw (and non-valid) data, therefore config is not applied.
|
|
|
|
* When file has been written (and contain valid data), we don't load new data since modification time remains the same.
|
|
|
|
*/
|
|
|
|
if (!loaded_config.loaded_from_preprocessed)
|
|
|
|
files = std::move(new_files);
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
updater(loaded_config.configuration);
|
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
|
|
|
if (throw_on_error)
|
|
|
|
throw;
|
|
|
|
tryLogCurrentException(log, "Error updating configuration from `" + path + "' config.");
|
|
|
|
}
|
|
|
|
}
|
2017-03-17 00:44:00 +00:00
|
|
|
}
|
2016-10-10 08:44:52 +00:00
|
|
|
|
2017-03-17 00:44:00 +00:00
|
|
|
struct ConfigReloader::FileWithTimestamp
|
2016-10-10 08:44:52 +00:00
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
std::string path;
|
|
|
|
time_t modification_time;
|
2016-01-17 13:34:36 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
FileWithTimestamp(const std::string & path_, time_t modification_time_)
|
|
|
|
: path(path_), modification_time(modification_time_) {}
|
2016-10-10 08:44:52 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
bool operator < (const FileWithTimestamp & rhs) const
|
|
|
|
{
|
|
|
|
return path < rhs.path;
|
|
|
|
}
|
2016-01-17 13:34:36 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
static bool isTheSame(const FileWithTimestamp & lhs, const FileWithTimestamp & rhs)
|
|
|
|
{
|
|
|
|
return (lhs.modification_time == rhs.modification_time) && (lhs.path == rhs.path);
|
|
|
|
}
|
2017-03-17 00:44:00 +00:00
|
|
|
};
|
2016-10-10 08:44:52 +00:00
|
|
|
|
|
|
|
|
2017-03-17 00:44:00 +00:00
|
|
|
void ConfigReloader::FilesChangesTracker::addIfExists(const std::string & path)
|
2016-10-10 08:44:52 +00:00
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
if (!path.empty() && Poco::File(path).exists())
|
|
|
|
{
|
|
|
|
files.emplace(path, Poco::File(path).getLastModified().epochTime());
|
|
|
|
}
|
2017-03-17 00:44:00 +00:00
|
|
|
}
|
2016-10-10 08:44:52 +00:00
|
|
|
|
2017-03-17 00:44:00 +00:00
|
|
|
bool ConfigReloader::FilesChangesTracker::isDifferOrNewerThan(const FilesChangesTracker & rhs)
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
return (files.size() != rhs.files.size()) ||
|
|
|
|
!std::equal(files.begin(), files.end(), rhs.files.begin(), FileWithTimestamp::isTheSame);
|
2016-01-17 13:34:36 +00:00
|
|
|
}
|
|
|
|
|
2017-03-17 00:44:00 +00:00
|
|
|
ConfigReloader::FilesChangesTracker ConfigReloader::getNewFileList() const
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
FilesChangesTracker file_list;
|
2017-03-17 00:44:00 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
file_list.addIfExists(path);
|
|
|
|
file_list.addIfExists(include_from_path);
|
2017-03-17 00:44:00 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
for (const auto & merge_path : ConfigProcessor::getConfigMergeFiles(path))
|
|
|
|
file_list.addIfExists(merge_path);
|
2017-03-17 00:44:00 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
return file_list;
|
2017-03-17 00:44:00 +00:00
|
|
|
}
|
2016-01-17 13:34:36 +00:00
|
|
|
|
|
|
|
}
|