| 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 | |