More simple time zones implementation [#CLICKHOUSE-2765].

This commit is contained in:
Alexey Milovidov 2017-01-22 12:27:51 +03:00
parent bcdf3ce82c
commit f41480f1cd
2 changed files with 22 additions and 96 deletions

View File

@ -3,14 +3,13 @@
#include <common/DateLUTImpl.h>
#include <common/singleton.h>
#include <DB/Core/Defines.h>
#include <Poco/Exception.h>
#include <unordered_map>
#include <vector>
#include <atomic>
#include <mutex>
#include <memory>
/// This class provides lazy initialization and lookup of singleton DateLUTImpl objects for a given timezone.
class DateLUT : public Singleton<DateLUT>
{
@ -48,34 +47,13 @@ protected:
DateLUT();
private:
ALWAYS_INLINE const DateLUTImpl & getImplementation(const std::string & time_zone) const
{
auto it = time_zone_to_group.find(time_zone);
if (it == time_zone_to_group.end())
throw Poco::Exception("Invalid time zone " + time_zone);
size_t group_id = it->second;
auto initialize_impl = [this, group_id, &time_zone]()
{
date_lut_impls[group_id] = std::make_unique<DateLUTImpl>(time_zone);
};
std::call_once(initialized_flags[group_id], initialize_impl);
return *date_lut_impls[group_id];
}
private:
/// A mapping of a time zone name into a group id of equivalent time zones.
/// Two time zones are considered equivalent if they have the same properties.
using TimeZoneToGroup = std::unordered_map<std::string, size_t>;
TimeZoneToGroup time_zone_to_group;
const DateLUTImpl & getImplementation(const std::string & time_zone) const;
using DateLUTImplPtr = std::unique_ptr<DateLUTImpl>;
/// A vector of lookup tables indexed by group id and their initialization flags.
mutable std::vector<DateLUTImplPtr> date_lut_impls;
mutable std::vector<std::once_flag> initialized_flags;
/// Time zone name -> implementation.
mutable std::unordered_map<std::string, DateLUTImplPtr> impls;
mutable std::mutex mutex;
std::atomic<const DateLUTImpl *> default_impl;
};

View File

@ -1,5 +1,7 @@
#include <common/DateLUT.h>
#include <Poco/Exception.h>
#pragma GCC diagnostic push
#ifdef __APPLE__
#pragma GCC diagnostic ignored "-Wold-style-cast"
@ -8,85 +10,31 @@
#include <unicode/unistr.h>
#pragma GCC diagnostic pop
DateLUT::DateLUT()
{
using namespace icu;
/// Initialize the list of all time zones.
std::unique_ptr<StringEnumeration> time_zone_ids(TimeZone::createEnumeration());
if (time_zone_ids == nullptr)
throw Poco::Exception("Failed to query the list of time zones.");
UErrorCode status = U_ZERO_ERROR;
const UnicodeString * zone_id = time_zone_ids->snext(status);
if (zone_id == nullptr)
throw Poco::Exception("No time zone available.");
std::vector<UnicodeString> time_zones;
while ((zone_id != nullptr) && (status == U_ZERO_ERROR))
{
time_zones.push_back(*zone_id);
zone_id = time_zone_ids->snext(status);
}
size_t group_id = 0;
for (const auto & time_zone : time_zones)
{
const UnicodeString & u_group_name = TimeZone::getEquivalentID(time_zone, 0);
std::string group_name;
if (u_group_name.isEmpty())
{
time_zone.toUTF8String(group_name);
auto res = time_zone_to_group.insert(std::make_pair(group_name, group_id));
if (!res.second)
throw Poco::Exception("Failed to initialize time zone information.");
++group_id;
}
else
{
u_group_name.toUTF8String(group_name);
auto it = time_zone_to_group.find(group_name);
if (it == time_zone_to_group.end())
{
auto count = TimeZone::countEquivalentIDs(time_zone);
if (count == 0)
throw Poco::Exception("Inconsistent time zone information.");
for (auto i = 0; i < count; ++i)
{
const UnicodeString & u_name = TimeZone::getEquivalentID(time_zone, i);
std::string name;
u_name.toUTF8String(name);
auto res = time_zone_to_group.insert(std::make_pair(name, group_id));
if (!res.second)
throw Poco::Exception("Failed to initialize time zone information.");
}
++group_id;
}
}
}
if (group_id == 0)
throw Poco::Exception("Could not find any time zone information.");
date_lut_impls.resize(group_id);
initialized_flags = std::vector<std::once_flag>(group_id);
/// Initialize the pointer to the default DateLUTImpl.
std::unique_ptr<TimeZone> tz(TimeZone::createDefault());
std::unique_ptr<icu::TimeZone> tz(icu::TimeZone::createDefault());
if (tz == nullptr)
throw Poco::Exception("Failed to determine the host time zone.");
UnicodeString u_out;
icu::UnicodeString u_out;
tz->getID(u_out);
std::string default_time_zone;
u_out.toUTF8String(default_time_zone);
default_impl.store(&getImplementation(default_time_zone), std::memory_order_release);
}
const DateLUTImpl & DateLUT::getImplementation(const std::string & time_zone) const
{
std::lock_guard<std::mutex> lock(mutex);
auto it = impls.find(time_zone);
if (it == impls.end())
it->second = std::make_unique<DateLUTImpl>(time_zone);
return it->second;
}