Skip to content

Commit 73ec715

Browse files
committed
revert to tile expiry
1 parent 16dba7c commit 73ec715

10 files changed

Lines changed: 162 additions & 409 deletions

flex-config/gen/grouped-linemerge.lua

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,13 @@
2222
-- * Apply an update: osm2pgsql -a -O flex -S grouped-linemerge.lua CHANGES.osc.gz
2323
-- * Update the merged table: osm2pgsql-gen -a -S grouped-linemerge.lua
2424

25-
-- An expire output with an 'endpoint_table' records the exact endpoints (start
26-
-- and end point) of every way added/edited/deleted during an update, as POINT
27-
-- rows. The grouped-linemerge generalization consumes these points: it walks
28-
-- each affected connected component out from the changed endpoints and
29-
-- re-merges only those, matching by exact endpoint equality (no tiles, no
30-
-- area scan). Deletes contribute the old way's endpoints automatically.
25+
-- An expire output records which tiles changed during an update. The
26+
-- grouped-linemerge generalization uses it only as a seed for "where did line
27+
-- geometry change" - it then walks each affected connected component out from
28+
-- there and re-merges it. Use a high maxzoom so the seed regions are small.
3129
local exp_roads = osm2pgsql.define_expire_output({
32-
endpoint_table = 'exp_roads_endpoints',
30+
maxzoom = 18,
31+
table = 'exp_roads',
3332
})
3433

3534
-- The source table with the original road segments (one row per OSM way).
@@ -42,7 +41,7 @@ local roads = osm2pgsql.define_table({
4241
{ column = 'highway', type = 'text' },
4342
{ column = 'layer', type = 'int' },
4443
-- Attach the expire output to the geometry so that any change to a
45-
-- road's geometry (add/modify/delete) records its endpoints.
44+
-- road's geometry (add/modify/delete) expires the tiles it covers.
4645
{ column = 'geom', type = 'linestring', not_null = true,
4746
expire = { { output = exp_roads } } },
4847
}
@@ -94,10 +93,10 @@ function osm2pgsql.process_gen()
9493
-- Here we only merge roads that carry a label or a shield.
9594
where = 'name IS NOT NULL OR ref IS NOT NULL',
9695

97-
-- In append mode, the table of exact changed-way endpoints to consume
98-
-- (written by the expire output's 'endpoint_table' above). Consumption
99-
-- is destructive, so each generalizer needs its own endpoint table.
100-
endpoint_table = 'exp_roads_endpoints',
96+
-- In append mode, where to read the expired tiles from, and the zoom
97+
-- level they were captured at (must match the expire output's maxzoom).
98+
expire_list = 'exp_roads',
99+
zoom = 18,
101100

102101
-- Create functional endpoint indexes on the src/dest tables in create
103102
-- mode. These make the incremental component walk fast. Set to false

src/expire-output.cpp

Lines changed: 11 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,9 @@
1010
#include "expire-output.hpp"
1111

1212
#include "format.hpp"
13-
#include "geom.hpp"
14-
#include "hex.hpp"
1513
#include "logging.hpp"
1614
#include "pgsql.hpp"
1715
#include "tile.hpp"
18-
#include "wkb.hpp"
1916

2017
#include <cerrno>
2118
#include <system_error>
@@ -53,43 +50,10 @@ void expire_output_t::add_tiles(
5350
m_tiles.insert(dirty_tiles.cbegin(), dirty_tiles.cend());
5451
}
5552

56-
void expire_output_t::add_endpoints(geom::geometry_t const &geom)
57-
{
58-
auto const add_line = [this](geom::linestring_t const &line) {
59-
if (line.empty()) {
60-
return;
61-
}
62-
auto const &first = line.front();
63-
auto const &last = line.back();
64-
m_endpoints.emplace(first.x(), first.y());
65-
m_endpoints.emplace(last.x(), last.y());
66-
};
67-
68-
std::lock_guard<std::mutex> const guard{*m_tiles_mutex};
69-
70-
m_endpoint_srid = geom.srid();
71-
if (geom.is_linestring()) {
72-
add_line(geom.get<geom::linestring_t>());
73-
} else if (geom.is_multilinestring()) {
74-
for (auto const &line : geom.get<geom::multilinestring_t>()) {
75-
add_line(line);
76-
}
77-
}
78-
}
79-
8053
bool expire_output_t::empty() noexcept
8154
{
8255
std::lock_guard<std::mutex> const guard{*m_tiles_mutex};
83-
return m_tiles.empty() && m_endpoints.empty();
84-
}
85-
86-
std::vector<std::pair<double, double>> expire_output_t::get_endpoints()
87-
{
88-
std::lock_guard<std::mutex> const guard{*m_tiles_mutex};
89-
std::vector<std::pair<double, double>> endpoints(m_endpoints.cbegin(),
90-
m_endpoints.cend());
91-
m_endpoints.clear();
92-
return endpoints;
56+
return m_tiles.empty();
9357
}
9458

9559
quadkey_list_t expire_output_t::get_tiles()
@@ -115,9 +79,6 @@ expire_output_t::output(connection_params_t const &connection_params)
11579
if (!m_table.empty()) {
11680
num = output_tiles_to_table(get_tiles(), connection_params);
11781
}
118-
if (!m_endpoint_table.empty()) {
119-
num += output_endpoints_to_table(get_endpoints(), connection_params);
120-
}
12182
return num;
12283
}
12384

@@ -179,58 +140,16 @@ std::size_t expire_output_t::output_tiles_to_table(
179140
return count;
180141
}
181142

182-
std::size_t expire_output_t::output_endpoints_to_table(
183-
std::vector<std::pair<double, double>> const &endpoints,
184-
connection_params_t const &connection_params) const
185-
{
186-
if (endpoints.empty()) {
187-
return 0;
188-
}
189-
190-
auto const qn = qualified_name(m_schema, m_endpoint_table);
191-
192-
pg_conn_t const db_connection{connection_params, "expire"};
193-
194-
// COPY is significantly faster than individual INSERTs.
195-
db_connection.copy_start(fmt::format("COPY {} (geom) FROM STDIN", qn));
196-
197-
std::string buffer;
198-
for (auto const &[x, y] : endpoints) {
199-
geom::geometry_t const point{geom::point_t{x, y}, m_endpoint_srid};
200-
buffer += util::encode_hex(geom_to_ewkb(point));
201-
buffer += '\n';
202-
if (buffer.size() >= 65536) {
203-
db_connection.copy_send(buffer, qn);
204-
buffer.clear();
205-
}
206-
}
207-
if (!buffer.empty()) {
208-
db_connection.copy_send(buffer, qn);
209-
}
210-
db_connection.copy_end(qn);
211-
212-
return endpoints.size();
213-
}
214-
215143
void expire_output_t::create_output_table(pg_conn_t const &db_connection) const
216144
{
217-
if (!m_table.empty()) {
218-
auto const qn = qualified_name(m_schema, m_table);
219-
db_connection.exec(
220-
"CREATE TABLE IF NOT EXISTS {} ("
221-
" zoom int4 NOT NULL,"
222-
" x int4 NOT NULL,"
223-
" y int4 NOT NULL,"
224-
" first timestamp with time zone DEFAULT CURRENT_TIMESTAMP(0),"
225-
" last timestamp with time zone DEFAULT CURRENT_TIMESTAMP(0),"
226-
" PRIMARY KEY (zoom, x, y))",
227-
qn);
228-
}
229-
230-
if (!m_endpoint_table.empty()) {
231-
auto const qn = qualified_name(m_schema, m_endpoint_table);
232-
db_connection.exec("CREATE TABLE IF NOT EXISTS {} ("
233-
" geom geometry(Point) NOT NULL)",
234-
qn);
235-
}
145+
auto const qn = qualified_name(m_schema, m_table);
146+
db_connection.exec(
147+
"CREATE TABLE IF NOT EXISTS {} ("
148+
" zoom int4 NOT NULL,"
149+
" x int4 NOT NULL,"
150+
" y int4 NOT NULL,"
151+
" first timestamp with time zone DEFAULT CURRENT_TIMESTAMP(0),"
152+
" last timestamp with time zone DEFAULT CURRENT_TIMESTAMP(0),"
153+
" PRIMARY KEY (zoom, x, y))",
154+
qn);
236155
}

src/expire-output.hpp

Lines changed: 0 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -17,22 +17,16 @@
1717
#include <cstdint>
1818
#include <memory>
1919
#include <mutex>
20-
#include <set>
2120
#include <string>
2221
#include <unordered_set>
2322
#include <utility>
24-
#include <vector>
2523

2624
constexpr std::size_t DEFAULT_MAX_TILES_GEOMETRY = 10'000'000;
2725
constexpr std::size_t DEFAULT_MAX_TILES_OVERALL = 50'000'000;
2826

2927
class pg_conn_t;
3028
class connection_params_t;
3129

32-
namespace geom {
33-
class geometry_t;
34-
} // namespace geom
35-
3630
/**
3731
* Output for tile expiry.
3832
*/
@@ -59,35 +53,6 @@ class expire_output_t
5953
m_table = std::move(table);
6054
}
6155

62-
std::string const &endpoint_table() const noexcept
63-
{
64-
return m_endpoint_table;
65-
}
66-
67-
void set_endpoint_table(std::string table)
68-
{
69-
m_endpoint_table = std::move(table);
70-
}
71-
72-
/// Does this output write expired tiles (to a file and/or table)?
73-
bool has_tile_output() const noexcept
74-
{
75-
return !m_filename.empty() || !m_table.empty();
76-
}
77-
78-
/// Does this output write the endpoints of changed geometries to a table?
79-
bool has_endpoint_output() const noexcept
80-
{
81-
return !m_endpoint_table.empty();
82-
}
83-
84-
/**
85-
* Record the endpoints (first and last point of each linestring) of a
86-
* changed geometry. They are written to the endpoint table on output.
87-
* Non-(multi)linestring geometries contribute no endpoints. Thread-safe.
88-
*/
89-
void add_endpoints(geom::geometry_t const &geom);
90-
9156
uint32_t minzoom() const noexcept { return m_minzoom; }
9257
void set_minzoom(uint32_t minzoom) noexcept { m_minzoom = minzoom; }
9358

@@ -151,19 +116,6 @@ class expire_output_t
151116
output_tiles_to_table(quadkey_list_t const &tiles_at_maxzoom,
152117
connection_params_t const &connection_params) const;
153118

154-
/// Take and clear the collected endpoints. Thread-safe.
155-
std::vector<std::pair<double, double>> get_endpoints();
156-
157-
/**
158-
* Write the collected endpoints as POINT geometries to the endpoint table.
159-
*
160-
* \param endpoints The endpoint coordinates to write
161-
* \param connection_params Database connection parameters
162-
*/
163-
std::size_t
164-
output_endpoints_to_table(std::vector<std::pair<double, double>> const &endpoints,
165-
connection_params_t const &connection_params) const;
166-
167119
/**
168120
* Access to the m_tiles collection of expired tiles must go through
169121
* this mutex, because it can happend from several threads at the same
@@ -184,16 +136,6 @@ class expire_output_t
184136
/// The table (if any) for output
185137
std::string m_table;
186138

187-
/// The table (if any) for changed-geometry endpoints
188-
std::string m_endpoint_table;
189-
190-
/// Collected endpoints (deduplicated) of changed geometries. Guarded by
191-
/// m_tiles_mutex (same access pattern as m_tiles).
192-
std::set<std::pair<double, double>> m_endpoints;
193-
194-
/// SRID of the collected endpoints (all geometries share the table's SRID).
195-
int m_endpoint_srid = 0;
196-
197139
/// Minimum zoom level for output
198140
uint32_t m_minzoom = 0;
199141

src/flex-lua-expire-output.cpp

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -39,20 +39,10 @@ create_expire_output(lua_State *lua_state, std::string const &default_schema,
3939
new_expire_output.set_schema_and_table(schema, table);
4040
lua_pop(lua_state, 2); // "schema" and "table"
4141

42-
// optional "endpoint_table" field: write the endpoints of changed
43-
// geometries as POINT rows (in the same schema) instead of, or in addition
44-
// to, expired tiles.
45-
auto const *endpoint_table = luaX_get_table_string(
46-
lua_state, "endpoint_table", -1, "The expire output", "");
47-
check_identifier(endpoint_table, "endpoint_table field");
48-
new_expire_output.set_endpoint_table(endpoint_table);
49-
lua_pop(lua_state, 1); // "endpoint_table"
50-
5142
if (new_expire_output.filename().empty() &&
52-
new_expire_output.table().empty() &&
53-
new_expire_output.endpoint_table().empty()) {
54-
throw std::runtime_error{"Must set 'filename', 'table', and/or "
55-
"'endpoint_table' on expire output."};
43+
new_expire_output.table().empty()) {
44+
throw std::runtime_error{
45+
"Must set 'filename' and/or 'table' on expire output."};
5646
}
5747

5848
// required "maxzoom" field

src/flex-table-column.cpp

Lines changed: 10 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -339,34 +339,17 @@ void flex_table_column_t::do_expire(
339339

340340
for (auto const &expire_config : m_expires) {
341341
assert(expire_config.expire_output < expire->size());
342-
auto &expire_output = expire_outputs->at(expire_config.expire_output);
343-
344-
if (expire_output.has_tile_output()) {
345-
auto &expire_tiles = expire->at(expire_config.expire_output);
346-
if (!expire_config.diff_expire || !enable_diff_expire ||
347-
geoms_old->empty() || geoms_new->empty()) {
348-
separate_expire(*geoms_old, expire_config, expire_tiles,
349-
expire_outputs);
350-
separate_expire(*geoms_new, expire_config, expire_tiles,
351-
expire_outputs);
352-
} else {
353-
diff_expire(geoms_old, geoms_new, expire_config, expire_tiles,
354-
expire_outputs);
355-
}
356-
}
342+
auto &expire_tiles = expire->at(expire_config.expire_output);
357343

358-
// Record the endpoints of the changed geometry (old and new), so a
359-
// consumer (e.g. the grouped-linemerge generalizer) can re-merge only
360-
// the exact connected components touched, instead of everything in a
361-
// tile. Deletes provide the old geometry via the geometry cache, so
362-
// their endpoints are captured here too.
363-
if (expire_output.has_endpoint_output()) {
364-
for (auto const &geom : *geoms_old) {
365-
expire_output.add_endpoints(geom);
366-
}
367-
for (auto const &geom : *geoms_new) {
368-
expire_output.add_endpoints(geom);
369-
}
344+
if (!expire_config.diff_expire || !enable_diff_expire ||
345+
geoms_old->empty() || geoms_new->empty()) {
346+
separate_expire(*geoms_old, expire_config, expire_tiles,
347+
expire_outputs);
348+
separate_expire(*geoms_new, expire_config, expire_tiles,
349+
expire_outputs);
350+
} else {
351+
diff_expire(geoms_old, geoms_new, expire_config, expire_tiles,
352+
expire_outputs);
370353
}
371354
}
372355
}

0 commit comments

Comments
 (0)