2018-11-28 11:37:12 +00:00
|
|
|
#include "RegionsHierarchy.h"
|
2017-01-21 04:24:28 +00:00
|
|
|
|
2018-11-28 11:37:12 +00:00
|
|
|
#include "GeodataProviders/IHierarchiesProvider.h"
|
2017-01-21 04:24:28 +00:00
|
|
|
#include <Poco/Util/Application.h>
|
|
|
|
#include <Poco/Exception.h>
|
|
|
|
#include <common/logger_useful.h>
|
2017-07-10 04:34:14 +00:00
|
|
|
#include <ext/singleton.h>
|
2017-04-01 09:19:00 +00:00
|
|
|
#include <IO/WriteHelpers.h>
|
2017-01-21 04:24:28 +00:00
|
|
|
|
|
|
|
|
2018-11-22 21:19:58 +00:00
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
namespace ErrorCodes
|
|
|
|
{
|
|
|
|
extern const int INCORRECT_DATA;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-11-28 22:15:06 +00:00
|
|
|
RegionsHierarchy::RegionsHierarchy(IRegionsHierarchyDataSourcePtr data_source_)
|
|
|
|
: data_source(data_source_)
|
2017-01-21 04:24:28 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void RegionsHierarchy::reload()
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
Logger * log = &Logger::get("RegionsHierarchy");
|
|
|
|
|
2017-11-28 22:15:06 +00:00
|
|
|
if (!data_source->isModified())
|
2017-04-01 07:20:54 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
LOG_DEBUG(log, "Reloading regions hierarchy");
|
|
|
|
|
|
|
|
const size_t initial_size = 10000;
|
|
|
|
const size_t max_size = 15000000;
|
|
|
|
|
|
|
|
RegionParents new_parents(initial_size);
|
|
|
|
RegionParents new_city(initial_size);
|
|
|
|
RegionParents new_country(initial_size);
|
|
|
|
RegionParents new_area(initial_size);
|
|
|
|
RegionParents new_district(initial_size);
|
|
|
|
RegionParents new_continent(initial_size);
|
|
|
|
RegionParents new_top_continent(initial_size);
|
|
|
|
RegionPopulations new_populations(initial_size);
|
2018-11-26 00:56:50 +00:00
|
|
|
RegionDepths new_depths(initial_size);
|
2017-04-01 07:20:54 +00:00
|
|
|
RegionTypes types(initial_size);
|
|
|
|
|
|
|
|
RegionID max_region_id = 0;
|
|
|
|
|
2018-05-07 02:01:11 +00:00
|
|
|
auto regions_reader = data_source->createReader();
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2017-11-28 22:15:06 +00:00
|
|
|
RegionEntry region_entry;
|
2017-12-04 14:35:03 +00:00
|
|
|
while (regions_reader->readNext(region_entry))
|
2017-11-28 22:15:06 +00:00
|
|
|
{
|
|
|
|
if (region_entry.id > max_region_id)
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
2017-11-28 22:15:06 +00:00
|
|
|
if (region_entry.id > max_size)
|
2018-11-22 21:19:58 +00:00
|
|
|
throw DB::Exception("Region id is too large: " + DB::toString(region_entry.id) + ", should be not more than " + DB::toString(max_size),
|
|
|
|
DB::ErrorCodes::INCORRECT_DATA);
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2017-11-28 22:15:06 +00:00
|
|
|
max_region_id = region_entry.id;
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2017-11-28 22:15:06 +00:00
|
|
|
while (region_entry.id >= new_parents.size())
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
|
|
|
new_parents.resize(new_parents.size() * 2);
|
|
|
|
new_populations.resize(new_parents.size());
|
|
|
|
types.resize(new_parents.size());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-28 22:15:06 +00:00
|
|
|
new_parents[region_entry.id] = region_entry.parent_id;
|
|
|
|
new_populations[region_entry.id] = region_entry.population;
|
|
|
|
types[region_entry.id] = region_entry.type;
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
|
|
|
|
2017-11-16 17:40:54 +00:00
|
|
|
new_parents .resize(max_region_id + 1);
|
|
|
|
new_city .resize(max_region_id + 1);
|
|
|
|
new_country .resize(max_region_id + 1);
|
|
|
|
new_area .resize(max_region_id + 1);
|
|
|
|
new_district .resize(max_region_id + 1);
|
2017-04-01 07:20:54 +00:00
|
|
|
new_continent .resize(max_region_id + 1);
|
|
|
|
new_top_continent.resize(max_region_id + 1);
|
2017-11-16 17:40:54 +00:00
|
|
|
new_populations .resize(max_region_id + 1);
|
|
|
|
new_depths .resize(max_region_id + 1);
|
2017-04-01 07:20:54 +00:00
|
|
|
types .resize(max_region_id + 1);
|
|
|
|
|
|
|
|
/// prescribe the cities and countries for the regions
|
|
|
|
for (RegionID i = 0; i <= max_region_id; ++i)
|
|
|
|
{
|
2017-11-16 18:47:59 +00:00
|
|
|
if (types[i] == RegionType::City)
|
2017-04-01 07:20:54 +00:00
|
|
|
new_city[i] = i;
|
|
|
|
|
2017-11-16 18:47:59 +00:00
|
|
|
if (types[i] == RegionType::Area)
|
2017-04-01 07:20:54 +00:00
|
|
|
new_area[i] = i;
|
|
|
|
|
2017-11-16 18:47:59 +00:00
|
|
|
if (types[i] == RegionType::District)
|
2017-04-01 07:20:54 +00:00
|
|
|
new_district[i] = i;
|
|
|
|
|
2017-11-16 18:47:59 +00:00
|
|
|
if (types[i] == RegionType::Country)
|
2017-04-01 07:20:54 +00:00
|
|
|
new_country[i] = i;
|
|
|
|
|
2017-11-16 18:47:59 +00:00
|
|
|
if (types[i] == RegionType::Continent)
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
|
|
|
new_continent[i] = i;
|
|
|
|
new_top_continent[i] = i;
|
|
|
|
}
|
|
|
|
|
|
|
|
RegionDepth depth = 0;
|
|
|
|
RegionID current = i;
|
|
|
|
while (true)
|
|
|
|
{
|
|
|
|
++depth;
|
|
|
|
|
|
|
|
if (depth == std::numeric_limits<RegionDepth>::max())
|
|
|
|
throw Poco::Exception("Logical error in regions hierarchy: region " + DB::toString(current) + " possible is inside infinite loop");
|
|
|
|
|
|
|
|
current = new_parents[current];
|
|
|
|
if (current == 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (current > max_region_id)
|
|
|
|
throw Poco::Exception("Logical error in regions hierarchy: region " + DB::toString(current) + " (specified as parent) doesn't exist");
|
|
|
|
|
2017-11-16 18:47:59 +00:00
|
|
|
if (types[current] == RegionType::City)
|
2017-04-01 07:20:54 +00:00
|
|
|
new_city[i] = current;
|
|
|
|
|
2017-11-16 18:47:59 +00:00
|
|
|
if (types[current] == RegionType::Area)
|
2017-04-01 07:20:54 +00:00
|
|
|
new_area[i] = current;
|
|
|
|
|
2017-11-16 18:47:59 +00:00
|
|
|
if (types[current] == RegionType::District)
|
2017-04-01 07:20:54 +00:00
|
|
|
new_district[i] = current;
|
|
|
|
|
2017-11-16 18:47:59 +00:00
|
|
|
if (types[current] == RegionType::Country)
|
2017-04-01 07:20:54 +00:00
|
|
|
new_country[i] = current;
|
|
|
|
|
2017-11-16 18:47:59 +00:00
|
|
|
if (types[current] == RegionType::Continent)
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
|
|
|
if (!new_continent[i])
|
|
|
|
new_continent[i] = current;
|
|
|
|
new_top_continent[i] = current;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
new_depths[i] = depth;
|
|
|
|
}
|
|
|
|
|
|
|
|
parents.swap(new_parents);
|
|
|
|
country.swap(new_country);
|
|
|
|
city.swap(new_city);
|
|
|
|
area.swap(new_area);
|
|
|
|
district.swap(new_district);
|
|
|
|
continent.swap(new_continent);
|
|
|
|
top_continent.swap(new_top_continent);
|
|
|
|
populations.swap(new_populations);
|
|
|
|
depths.swap(new_depths);
|
2017-01-21 04:24:28 +00:00
|
|
|
}
|