-
-
Notifications
You must be signed in to change notification settings - Fork 477
Expand file tree
/
Copy pathosm2pgsql.cpp
More file actions
397 lines (329 loc) · 12.3 KB
/
osm2pgsql.cpp
File metadata and controls
397 lines (329 loc) · 12.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
/**
* SPDX-License-Identifier: GPL-2.0-or-later
*
* This file is part of osm2pgsql (https://osm2pgsql.org/).
*
* Copyright (C) 2006-2026 by the osm2pgsql developer community.
* For a full list of authors see the git log.
*/
#include "command-line-parser.hpp"
#include "input.hpp"
#include "logging.hpp"
#include "middle.hpp"
#include "options.hpp"
#include "osmdata.hpp"
#include "output.hpp"
#include "pgsql.hpp"
#include "pgsql-capabilities.hpp"
#include "properties.hpp"
#include "util.hpp"
#include "version.hpp"
#include <osmium/util/memory.hpp>
#include <exception>
#include <filesystem>
#include <memory>
#include <string>
#include <utility>
namespace {
/**
* Output overall memory usage as debug message.
*
* This only works on Linux.
*/
void show_memory_usage()
{
osmium::MemoryUsage const mem;
if (mem.peak() != 0) {
log_debug("Overall memory usage: peak={}MByte current={}MByte",
mem.peak(), mem.current());
}
}
file_info run(options_t const &options, properties_t *properties)
{
auto const files = prepare_input_files(
options.input_files, options.input_format, options.append);
auto thread_pool = std::make_shared<thread_pool_t>(
options.parallel_indexing ? options.num_procs : 1U);
log_debug("Started pool with {} threads.", thread_pool->num_threads());
auto middle = create_middle(thread_pool, options);
middle->start();
auto output = output_t::create_output(middle->get_query_instance(),
thread_pool, options, *properties);
middle->set_requirements(output->get_requirements());
if (!options.append) {
properties->init_table();
}
properties->store();
osmdata_t osmdata{middle, output, options};
// Processing: In this phase the input file(s) are read and parsed,
// populating some of the tables.
auto finfo = process_files(files, &osmdata, options.append,
get_logger().show_progress());
show_memory_usage();
// Process pending ways and relations. Cluster database tables and
// create indexes.
osmdata.stop();
return finfo;
}
void check_db(options_t const &options)
{
pg_conn_t const db_connection{options.connection_params, "check"};
init_database_capabilities(db_connection);
auto const pv = get_postgis_version();
if (pv.major < 3) {
throw std::runtime_error{"Need at least PostGIS version 3.0"};
}
check_schema(options.dbschema);
check_schema(options.middle_dbschema);
check_schema(options.output_dbschema);
}
// This is called in "create" mode to initialize properties.
void set_up_properties(properties_t *properties, options_t const &options)
{
properties->set_bool("attributes", options.extra_attributes);
if (options.flat_node_file.empty()) {
properties->set_string("flat_node_file", "");
} else {
properties->set_string(
"flat_node_file", std::filesystem::absolute(
std::filesystem::path{options.flat_node_file})
.string());
}
properties->set_string("prefix", options.prefix);
properties->set_bool("updatable", options.slim && !options.droptemp);
properties->set_string("version", get_osm2pgsql_short_version());
properties->set_int("db_format", options.middle_database_format);
properties->set_string("output", options.output_backend);
if (options.style.empty()) {
properties->set_string("style", "");
} else {
properties->set_string(
"style",
std::filesystem::absolute(std::filesystem::path{options.style})
.string());
}
}
void store_data_properties(properties_t *properties, file_info const &finfo)
{
if (finfo.last_timestamp.valid()) {
auto const timestamp = finfo.last_timestamp.to_iso();
properties->set_string("import_timestamp", timestamp);
properties->set_string("current_timestamp", timestamp);
}
for (std::string const s : {"base_url", "sequence_number", "timestamp"}) {
auto const value = finfo.header.get("osmosis_replication_" + s);
if (!value.empty()) {
properties->set_string("replication_" + s, value);
}
}
}
void check_updatable(properties_t const &properties)
{
if (properties.get_bool("updatable", false)) {
return;
}
throw std::runtime_error{
"This database is not updatable. To create an"
" updatable database use --slim (without --drop)."};
}
void check_attributes(properties_t const &properties, options_t *options)
{
bool const with_attributes = properties.get_bool("attributes", false);
if (options->extra_attributes) {
if (!with_attributes) {
throw std::runtime_error{
"Can not update with attributes (-x/--extra-attributes)"
" because original import was without attributes."};
}
return;
}
if (with_attributes) {
log_info("Updating with attributes (same as on import).");
options->extra_attributes = true;
}
}
void check_and_update_flat_node_file(properties_t *properties,
options_t *options)
{
auto const flat_node_file_from_import =
properties->get_string("flat_node_file", "");
if (options->flat_node_file.empty()) {
if (flat_node_file_from_import.empty()) {
log_info("Not using flat node file (same as on import).");
} else {
options->flat_node_file = flat_node_file_from_import;
log_info("Using flat node file '{}' (same as on import).",
flat_node_file_from_import);
}
} else {
auto const absolute_path =
std::filesystem::absolute(
std::filesystem::path{options->flat_node_file})
.string();
if (flat_node_file_from_import.empty()) {
throw fmt_error("Database was imported without flat node file. Can"
" not use flat node file '{}' now.",
options->flat_node_file);
}
if (absolute_path == flat_node_file_from_import) {
log_info("Using flat node file '{}' (same as on import).",
flat_node_file_from_import);
} else {
log_info(
"Using the flat node file you specified on the command line"
" ('{}') instead of the one used on import ('{}').",
absolute_path, flat_node_file_from_import);
properties->set_string("flat_node_file", absolute_path);
}
}
}
void check_prefix(properties_t const &properties, options_t *options)
{
auto const prefix = properties.get_string("prefix", "planet_osm");
if (!options->prefix_is_set) {
log_info("Using prefix '{}' (same as on import).", prefix);
options->prefix = prefix;
return;
}
if (prefix != options->prefix) {
throw fmt_error("Different prefix specified on command line ('{}')"
" then used on import ('{}').",
options->prefix, prefix);
}
}
void check_db_format(properties_t const &properties, options_t *options)
{
auto const format = properties.get_int("db_format", -1);
if (format == 1) {
throw std::runtime_error{
"Old database format detected. This version of osm2pgsql can not "
"read this any more. Downgrade osm2pgsql or reimport database."};
}
if (format != 2) {
throw fmt_error("Unknown db_format '{}' in properties.", format);
}
options->middle_database_format = static_cast<uint8_t>(format);
}
void check_output(properties_t const &properties, options_t *options)
{
auto const output = properties.get_string("output", "pgsql");
if (options->output_backend.empty()) {
options->output_backend = output;
log_info("Using output '{}' (same as on import).", output);
return;
}
if (options->output_backend == output) {
return;
}
throw fmt_error("Different output specified on command line ('{}')"
" then used on import ('{}').",
options->output_backend, output);
}
void check_and_update_style_file(properties_t *properties, options_t *options)
{
auto const style_file_from_import = properties->get_string("style", "");
if (options->style.empty()) {
log_info("Using style file '{}' (same as on import).",
style_file_from_import);
options->style = style_file_from_import;
return;
}
if (style_file_from_import.empty()) {
throw std::runtime_error{"Style file from import is empty!?"};
}
auto const absolute_path =
std::filesystem::absolute(std::filesystem::path{options->style})
.string();
if (absolute_path == style_file_from_import) {
log_info("Using style file '{}' (same as on import).",
style_file_from_import);
return;
}
log_info("Using the style file you specified on the command line"
" ('{}') instead of the one used on import ('{}').",
absolute_path, style_file_from_import);
properties->set_string("style", absolute_path);
}
// This is called in "append" mode to check that the command line options are
// compatible with the properties stored in the database.
void check_and_update_properties(properties_t *properties, options_t *options)
{
check_updatable(*properties);
check_attributes(*properties, options);
check_and_update_flat_node_file(properties, options);
check_prefix(*properties, options);
check_db_format(*properties, options);
check_output(*properties, options);
check_and_update_style_file(properties, options);
}
void set_option_defaults(options_t *options)
{
if (options->output_backend.empty()) {
options->output_backend = "pgsql";
}
if (options->style.empty()) {
if (options->output_backend == "flex") {
throw std::runtime_error{"You have to set the config file "
"with the -S|--style option."};
}
if (options->output_backend == "pgsql") {
options->style = DEFAULT_STYLE;
}
}
}
} // anonymous namespace
// NOLINTNEXTLINE(bugprone-exception-escape)
int main(int argc, char *argv[])
{
try {
auto options = parse_command_line(argc, argv);
if (options.command == command_t::help) {
// Already handled inside parse_command_line()
return 0;
}
if (options.command == command_t::version) {
print_version("osm2pgsql");
return 0;
}
util::timer_t timer_overall;
check_db(options);
properties_t properties{options.connection_params,
options.middle_dbschema};
if (options.append) {
if (!properties.load()) {
throw std::runtime_error{
"Did not find table 'osm2pgsql_properties' in database. "
"Database too old? Wrong schema?"};
}
check_and_update_properties(&properties, &options);
properties.store();
auto const finfo = run(options, &properties);
if (finfo.last_timestamp.valid()) {
auto const current_timestamp =
properties.get_string("current_timestamp", "");
if (current_timestamp.empty() ||
(finfo.last_timestamp >
osmium::Timestamp{current_timestamp})) {
properties.set_string("current_timestamp",
finfo.last_timestamp.to_iso());
}
}
} else {
set_option_defaults(&options);
set_up_properties(&properties, options);
auto const finfo = run(options, &properties);
store_data_properties(&properties, finfo);
}
properties.store();
show_memory_usage();
log_info("osm2pgsql took {} overall.",
util::human_readable_duration(timer_overall.stop()));
} catch (std::exception const &e) {
log_error("{}", e.what());
return 1;
} catch (...) {
log_error("Unknown exception.");
return 1;
}
return 0;
}