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
11namespace DB
12{
13namespace ErrorCodes
14{
15 extern const int INCORRECT_DATA;
16}
17}
18
19
20RegionsNames::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
31std::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
43void 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