2015-01-21 11:39:48 +00:00
|
|
|
#include <DB/Interpreters/Dictionaries.h>
|
|
|
|
#include <DB/Dictionaries/DictionaryFactory.h>
|
2015-02-03 17:03:35 +00:00
|
|
|
#include <DB/Dictionaries/DictionaryStructure.h>
|
|
|
|
#include <DB/Dictionaries/IDictionarySource.h>
|
2015-02-06 10:35:35 +00:00
|
|
|
#include <statdaemons/ext/scope_guard.hpp>
|
2015-01-21 11:39:48 +00:00
|
|
|
|
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
|
2015-02-04 13:06:56 +00:00
|
|
|
namespace
|
|
|
|
{
|
|
|
|
std::string getDictionariesConfigPath(const Poco::Util::AbstractConfiguration & config)
|
|
|
|
{
|
2015-02-04 14:29:02 +00:00
|
|
|
const auto path = config.getString("dictionaries_config", "");
|
2015-02-04 13:06:56 +00:00
|
|
|
if (path.empty())
|
|
|
|
return path;
|
|
|
|
|
|
|
|
if (path[0] != '/')
|
|
|
|
{
|
|
|
|
const auto app_config_path = config.getString("config-file", "config.xml");
|
|
|
|
const auto config_dir = Poco::Path{app_config_path}.parent().toString();
|
|
|
|
const auto absolute_path = config_dir + path;
|
|
|
|
if (Poco::File{absolute_path}.exists())
|
|
|
|
return absolute_path;
|
|
|
|
}
|
|
|
|
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-26 15:27:51 +00:00
|
|
|
void Dictionaries::reloadExternals()
|
2015-01-21 11:39:48 +00:00
|
|
|
{
|
2015-02-04 13:06:56 +00:00
|
|
|
const auto config_path = getDictionariesConfigPath(Poco::Util::Application::instance().config());
|
2015-02-04 13:21:50 +00:00
|
|
|
const Poco::File config_file{config_path};
|
2015-01-22 14:32:38 +00:00
|
|
|
|
2015-02-09 10:10:25 +00:00
|
|
|
if (config_path.empty() || !config_file.exists())
|
2015-01-26 15:27:51 +00:00
|
|
|
{
|
2015-02-04 13:21:50 +00:00
|
|
|
LOG_WARNING(log, "config file '" + config_path + "' does not exist");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
const auto last_modified = config_file.getLastModified();
|
|
|
|
if (last_modified > dictionaries_last_modified)
|
|
|
|
{
|
|
|
|
/// definitions of dictionaries may have changed, recreate all of them
|
|
|
|
dictionaries_last_modified = last_modified;
|
2015-01-21 11:39:48 +00:00
|
|
|
|
2015-02-10 14:50:43 +00:00
|
|
|
const auto config = new Poco::Util::XMLConfiguration{config_path};
|
|
|
|
SCOPE_EXIT(
|
|
|
|
config->release();
|
|
|
|
);
|
2015-01-21 11:39:48 +00:00
|
|
|
|
2015-02-04 13:21:50 +00:00
|
|
|
/// get all dictionaries' definitions
|
|
|
|
Poco::Util::AbstractConfiguration::Keys keys;
|
|
|
|
config->keys(keys);
|
2015-01-26 15:27:51 +00:00
|
|
|
|
2015-02-04 13:21:50 +00:00
|
|
|
/// for each dictionary defined in xml config
|
|
|
|
for (const auto & key : keys)
|
2015-01-26 15:27:51 +00:00
|
|
|
{
|
2015-02-04 13:21:50 +00:00
|
|
|
try
|
2015-01-30 13:43:16 +00:00
|
|
|
{
|
2015-02-04 13:21:50 +00:00
|
|
|
if (0 != strncmp(key.data(), "dictionary", strlen("dictionary")))
|
|
|
|
{
|
|
|
|
LOG_WARNING(log, "unknown node in dictionaries file: '" + key + "', 'dictionary'");
|
|
|
|
continue;
|
|
|
|
}
|
2015-01-21 11:39:48 +00:00
|
|
|
|
2015-02-10 14:50:43 +00:00
|
|
|
const auto name = config->getString(key + ".name");
|
2015-02-04 13:21:50 +00:00
|
|
|
if (name.empty())
|
|
|
|
{
|
|
|
|
LOG_WARNING(log, "dictionary name cannot be empty");
|
|
|
|
continue;
|
|
|
|
}
|
2015-01-30 13:43:16 +00:00
|
|
|
|
2015-02-10 14:50:43 +00:00
|
|
|
auto dict_ptr = DictionaryFactory::instance().create(name, *config, key, context);
|
2015-02-04 13:21:50 +00:00
|
|
|
if (!dict_ptr->isCached())
|
|
|
|
{
|
|
|
|
const auto & lifetime = dict_ptr->getLifetime();
|
2015-02-04 15:18:29 +00:00
|
|
|
if (lifetime.min_sec != 0 && lifetime.max_sec != 0)
|
|
|
|
{
|
|
|
|
std::uniform_int_distribution<std::uint64_t> distribution{
|
|
|
|
lifetime.min_sec,
|
|
|
|
lifetime.max_sec
|
|
|
|
};
|
|
|
|
update_times[name] = std::chrono::system_clock::now() +
|
|
|
|
std::chrono::seconds{distribution(rnd_engine)};
|
|
|
|
}
|
2015-02-04 13:21:50 +00:00
|
|
|
}
|
2015-02-03 11:36:07 +00:00
|
|
|
|
2015-02-04 13:21:50 +00:00
|
|
|
auto it = external_dictionaries.find(name);
|
|
|
|
/// add new dictionary or update an existing version
|
|
|
|
if (it == std::end(external_dictionaries))
|
|
|
|
{
|
|
|
|
const std::lock_guard<std::mutex> lock{external_dictionaries_mutex};
|
|
|
|
external_dictionaries.emplace(name, std::make_shared<MultiVersion<IDictionary>>(dict_ptr.release()));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
it->second->set(dict_ptr.release());
|
|
|
|
}
|
|
|
|
catch (...)
|
2015-02-03 11:36:07 +00:00
|
|
|
{
|
2015-02-04 13:21:50 +00:00
|
|
|
handleException();
|
2015-02-03 11:36:07 +00:00
|
|
|
}
|
2015-01-26 15:27:51 +00:00
|
|
|
}
|
2015-01-21 11:39:48 +00:00
|
|
|
}
|
2015-01-26 15:27:51 +00:00
|
|
|
}
|
2015-02-04 13:21:50 +00:00
|
|
|
|
|
|
|
/// periodic update
|
|
|
|
for (auto & dictionary : external_dictionaries)
|
2015-01-26 15:27:51 +00:00
|
|
|
{
|
2015-02-04 13:21:50 +00:00
|
|
|
try
|
2015-01-21 11:39:48 +00:00
|
|
|
{
|
2015-02-04 13:21:50 +00:00
|
|
|
auto current = dictionary.second->get();
|
2015-02-04 15:18:29 +00:00
|
|
|
const auto & lifetime = current->getLifetime();
|
|
|
|
|
|
|
|
/// do not update dictionaries with zero as lifetime
|
|
|
|
if (lifetime.min_sec == 0 || lifetime.max_sec == 0)
|
|
|
|
continue;
|
|
|
|
|
2015-02-04 13:21:50 +00:00
|
|
|
/// update only non-cached dictionaries
|
|
|
|
if (!current->isCached())
|
2015-01-26 15:27:51 +00:00
|
|
|
{
|
2015-02-04 13:21:50 +00:00
|
|
|
auto & update_time = update_times[current->getName()];
|
2015-01-29 15:47:21 +00:00
|
|
|
|
2015-02-04 13:21:50 +00:00
|
|
|
/// check that timeout has passed
|
|
|
|
if (std::chrono::system_clock::now() < update_time)
|
|
|
|
continue;
|
2015-02-03 11:36:07 +00:00
|
|
|
|
2015-02-10 14:50:43 +00:00
|
|
|
SCOPE_EXIT(
|
2015-02-06 10:35:35 +00:00
|
|
|
/// calculate next update time
|
|
|
|
std::uniform_int_distribution<std::uint64_t> distribution{lifetime.min_sec, lifetime.max_sec};
|
|
|
|
update_time = std::chrono::system_clock::now() + std::chrono::seconds{distribution(rnd_engine)};
|
2015-02-10 14:50:43 +00:00
|
|
|
);
|
2015-02-06 10:35:35 +00:00
|
|
|
|
2015-02-04 13:21:50 +00:00
|
|
|
/// check source modified
|
|
|
|
if (current->getSource()->isModified())
|
|
|
|
{
|
|
|
|
/// create new version of dictionary
|
|
|
|
auto new_version = current->clone();
|
|
|
|
dictionary.second->set(new_version.release());
|
2015-01-26 15:27:51 +00:00
|
|
|
}
|
|
|
|
}
|
2015-02-04 13:21:50 +00:00
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
|
|
|
handleException();
|
2015-01-21 11:39:48 +00:00
|
|
|
}
|
|
|
|
}
|
2015-01-26 15:27:51 +00:00
|
|
|
}
|
2015-01-21 11:39:48 +00:00
|
|
|
|
|
|
|
}
|