1 | #include "RegionsNames.h" |
2 | |
3 | #include <IO/WriteHelpers.h> |
4 | #include <IO/WriteBufferFromString.h> |
5 | #include <IO/Operators.h> |
6 | #include <Poco/Exception.h> |
7 | #include <common/logger_useful.h> |
8 | #include "GeodataProviders/INamesProvider.h" |
9 | |
10 | |
11 | namespace DB |
12 | { |
13 | namespace ErrorCodes |
14 | { |
15 | extern const int INCORRECT_DATA; |
16 | } |
17 | } |
18 | |
19 | |
20 | RegionsNames::RegionsNames(IRegionsNamesDataProviderPtr data_provider) |
21 | { |
22 | for (size_t language_id = 0; language_id < total_languages; ++language_id) |
23 | { |
24 | const std::string & language = languages[language_id]; |
25 | names_sources[language_id] = data_provider->getLanguageRegionsNamesSource(language); |
26 | } |
27 | |
28 | reload(); |
29 | } |
30 | |
31 | std::string RegionsNames::dumpSupportedLanguagesNames() |
32 | { |
33 | DB::WriteBufferFromOwnString out; |
34 | for (size_t i = 0; i < total_languages; ++i) |
35 | { |
36 | if (i > 0) |
37 | out << ", " ; |
38 | out << '\'' << languages[i] << '\''; |
39 | } |
40 | return out.str(); |
41 | } |
42 | |
43 | void RegionsNames::reload() |
44 | { |
45 | Logger * log = &Logger::get("RegionsNames" ); |
46 | LOG_DEBUG(log, "Reloading regions names" ); |
47 | |
48 | RegionID max_region_id = 0; |
49 | for (size_t language_id = 0; language_id < total_languages; ++language_id) |
50 | { |
51 | const std::string & language = languages[language_id]; |
52 | |
53 | auto names_source = names_sources[language_id]; |
54 | |
55 | if (!names_source || !names_source->isModified()) |
56 | continue; |
57 | |
58 | LOG_DEBUG(log, "Reloading regions names for language: " << language); |
59 | |
60 | auto names_reader = names_source->createReader(); |
61 | |
62 | const size_t initial_size = 10000; |
63 | const size_t max_size = 15000000; |
64 | |
65 | Chars new_chars; |
66 | StringRefs new_names_refs(initial_size, StringRef("" , 0)); |
67 | |
68 | /// Allocate a continuous slice of memory, which is enough to store all names. |
69 | new_chars.reserve(names_source->estimateTotalSize()); |
70 | |
71 | RegionNameEntry name_entry; |
72 | while (names_reader->readNext(name_entry)) |
73 | { |
74 | size_t old_size = new_chars.size(); |
75 | |
76 | if (new_chars.capacity() < old_size + name_entry.name.length() + 1) |
77 | throw Poco::Exception("Logical error. Maybe size estimate of " + names_source->getSourceName() + " is wrong." ); |
78 | |
79 | new_chars.resize(old_size + name_entry.name.length() + 1); |
80 | memcpy(new_chars.data() + old_size, name_entry.name.c_str(), name_entry.name.length() + 1); |
81 | |
82 | if (name_entry.id > max_region_id) |
83 | { |
84 | max_region_id = name_entry.id; |
85 | |
86 | if (name_entry.id > max_size) |
87 | throw DB::Exception( |
88 | "Region id is too large: " + DB::toString(name_entry.id) + ", should be not more than " + DB::toString(max_size), |
89 | DB::ErrorCodes::INCORRECT_DATA); |
90 | } |
91 | |
92 | while (name_entry.id >= new_names_refs.size()) |
93 | new_names_refs.resize(new_names_refs.size() * 2, StringRef("" , 0)); |
94 | |
95 | new_names_refs[name_entry.id] = StringRef(new_chars.data() + old_size, name_entry.name.length()); |
96 | } |
97 | |
98 | chars[language_id].swap(new_chars); |
99 | names_refs[language_id].swap(new_names_refs); |
100 | } |
101 | |
102 | for (size_t language_id = 0; language_id < total_languages; ++language_id) |
103 | names_refs[language_id].resize(max_region_id + 1, StringRef("" , 0)); |
104 | } |
105 | |