mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-10 01:25:21 +00:00
More simple time zones implementation [#CLICKHOUSE-2765].
This commit is contained in:
parent
bcdf3ce82c
commit
f41480f1cd
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user