Skip to content

Commit b6ab0c6

Browse files
authored
Merge pull request #1908 from joto/prep-expire3
Various changes in preparation for flexible expiry config
2 parents a07f005 + 0fc7fe8 commit b6ab0c6

11 files changed

+302
-172
lines changed

src/expire-config.hpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#ifndef OSM2PGSQL_FLEX_EXPIRE_CONFIG_HPP
2+
#define OSM2PGSQL_FLEX_EXPIRE_CONFIG_HPP
3+
4+
/**
5+
* SPDX-License-Identifier: GPL-2.0-or-later
6+
*
7+
* This file is part of osm2pgsql (https://osm2pgsql.org/).
8+
*
9+
* Copyright (C) 2006-2023 by the osm2pgsql developer community.
10+
* For a full list of authors see the git log.
11+
*/
12+
13+
#include <cstdlib>
14+
15+
enum class expire_mode
16+
{
17+
full_area, // Expire all tiles covered by polygon.
18+
boundary_only, // Expire only tiles covered by polygon boundary.
19+
hybrid // "full_area" or "boundary_only" mode depending on full_area_limit.
20+
};
21+
22+
/**
23+
* These are the options used for tile expiry calculations.
24+
*/
25+
struct expire_config_t
26+
{
27+
/// Buffer around expired feature as fraction of the tile size.
28+
double buffer = 0.1;
29+
30+
/**
31+
* Maximum width/heigth of bbox of a (multi)polygon before hybrid mode
32+
* expiry switches from full-area to boundary-only expire.
33+
*/
34+
double full_area_limit = 0.0;
35+
36+
/// Expire mode.
37+
expire_mode mode = expire_mode::full_area;
38+
39+
}; // struct expire_config_t
40+
41+
#endif // OSM2PGSQL_FLEX_EXPIRE_CONFIG_HPP

src/expire-tiles.cpp

Lines changed: 70 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,10 @@
3434
#include "tile.hpp"
3535
#include "wkb.hpp"
3636

37-
// How many tiles worth of space to leave either side of a changed feature
38-
static constexpr double const tile_expiry_leeway = 0.1;
39-
40-
expire_tiles::expire_tiles(uint32_t max_zoom, double max_bbox,
37+
expire_tiles::expire_tiles(uint32_t max_zoom,
4138
std::shared_ptr<reprojection> projection)
42-
: m_projection(std::move(projection)), m_max_bbox(max_bbox),
43-
m_maxzoom(max_zoom), m_map_width(1U << m_maxzoom)
39+
: m_projection(std::move(projection)), m_maxzoom(max_zoom),
40+
m_map_width(1U << m_maxzoom)
4441
{}
4542

4643
void expire_tiles::expire_tile(uint32_t x, uint32_t y)
@@ -71,68 +68,94 @@ geom::point_t expire_tiles::coords_to_tile(geom::point_t const &point)
7168
m_map_width * (0.5 - c.y() / tile_t::earth_circumference)};
7269
}
7370

74-
void expire_tiles::from_point_list(geom::point_list_t const &list)
71+
void expire_tiles::from_point_list(geom::point_list_t const &list,
72+
expire_config_t const &expire_config)
7573
{
7674
for_each_segment(list, [&](geom::point_t const &a, geom::point_t const &b) {
77-
from_line(a, b);
75+
from_line_segment(a, b, expire_config);
7876
});
7977
}
8078

81-
void expire_tiles::from_geometry(geom::point_t const &geom)
79+
void expire_tiles::from_geometry(geom::point_t const &geom,
80+
expire_config_t const &expire_config)
8281
{
8382
geom::box_t const box = geom::envelope(geom);
84-
from_bbox(box);
83+
from_bbox(box, expire_config);
8584
}
8685

87-
void expire_tiles::from_geometry(geom::linestring_t const &geom)
86+
void expire_tiles::from_geometry(geom::linestring_t const &geom,
87+
expire_config_t const &expire_config)
8888
{
89-
from_point_list(geom);
89+
from_point_list(geom, expire_config);
9090
}
9191

92-
void expire_tiles::from_polygon_boundary(geom::polygon_t const &geom)
92+
void expire_tiles::from_polygon_boundary(geom::polygon_t const &geom,
93+
expire_config_t const &expire_config)
9394
{
94-
from_point_list(geom.outer());
95+
from_point_list(geom.outer(), expire_config);
9596
for (auto const &inner : geom.inners()) {
96-
from_point_list(inner);
97+
from_point_list(inner, expire_config);
9798
}
9899
}
99100

100-
void expire_tiles::from_geometry(geom::polygon_t const &geom)
101+
void expire_tiles::from_geometry(geom::polygon_t const &geom,
102+
expire_config_t const &expire_config)
101103
{
104+
if (expire_config.mode == expire_mode::boundary_only) {
105+
from_polygon_boundary(geom, expire_config);
106+
return;
107+
}
108+
102109
geom::box_t const box = geom::envelope(geom);
103-
if (from_bbox(box)) {
110+
if (from_bbox(box, expire_config)) {
104111
/* Bounding box too big - just expire tiles on the boundary */
105-
from_polygon_boundary(geom);
112+
from_polygon_boundary(geom, expire_config);
113+
}
114+
}
115+
116+
void expire_tiles::from_polygon_boundary(geom::multipolygon_t const &geom,
117+
expire_config_t const &expire_config)
118+
{
119+
for (auto const &sgeom : geom) {
120+
from_polygon_boundary(sgeom, expire_config);
106121
}
107122
}
108123

109-
void expire_tiles::from_geometry(geom::multipolygon_t const &geom)
124+
void expire_tiles::from_geometry(geom::multipolygon_t const &geom,
125+
expire_config_t const &expire_config)
110126
{
127+
if (expire_config.mode == expire_mode::boundary_only) {
128+
from_polygon_boundary(geom, expire_config);
129+
return;
130+
}
131+
111132
geom::box_t const box = geom::envelope(geom);
112-
if (from_bbox(box)) {
133+
if (from_bbox(box, expire_config)) {
113134
/* Bounding box too big - just expire tiles on the boundary */
114-
for (auto const &sgeom : geom) {
115-
from_polygon_boundary(sgeom);
116-
}
135+
from_polygon_boundary(geom, expire_config);
117136
}
118137
}
119138

120-
void expire_tiles::from_geometry(geom::geometry_t const &geom)
139+
void expire_tiles::from_geometry(geom::geometry_t const &geom,
140+
expire_config_t const &expire_config)
121141
{
122-
geom.visit([&](auto const &g) { from_geometry(g); });
142+
geom.visit([&](auto const &g) { from_geometry(g, expire_config); });
123143
}
124144

125-
void expire_tiles::from_geometry_if_3857(geom::geometry_t const &geom)
145+
void expire_tiles::from_geometry_if_3857(geom::geometry_t const &geom,
146+
expire_config_t const &expire_config)
126147
{
127148
if (geom.srid() == 3857) {
128-
from_geometry(geom);
149+
from_geometry(geom, expire_config);
129150
}
130151
}
131152

132153
/*
133154
* Expire tiles that a line crosses
134155
*/
135-
void expire_tiles::from_line(geom::point_t const &a, geom::point_t const &b)
156+
void expire_tiles::from_line_segment(geom::point_t const &a,
157+
geom::point_t const &b,
158+
expire_config_t const &expire_config)
136159
{
137160
auto tilec_a = coords_to_tile(a);
138161
auto tilec_b = coords_to_tile(b);
@@ -175,11 +198,11 @@ void expire_tiles::from_line(geom::point_t const &a, geom::point_t const &b)
175198
if (y1 > y2) {
176199
std::swap(y1, y2);
177200
}
178-
for (int x = x1 - tile_expiry_leeway; x <= x2 + tile_expiry_leeway;
201+
for (int x = x1 - expire_config.buffer; x <= x2 + expire_config.buffer;
179202
++x) {
180203
uint32_t const norm_x = normalise_tile_x_coord(x);
181-
for (int y = y1 - tile_expiry_leeway; y <= y2 + tile_expiry_leeway;
182-
++y) {
204+
for (int y = y1 - expire_config.buffer;
205+
y <= y2 + expire_config.buffer; ++y) {
183206
if (y >= 0) {
184207
expire_tile(norm_x, static_cast<uint32_t>(y));
185208
}
@@ -191,7 +214,8 @@ void expire_tiles::from_line(geom::point_t const &a, geom::point_t const &b)
191214
/*
192215
* Expire tiles within a bounding box
193216
*/
194-
int expire_tiles::from_bbox(geom::box_t const &box)
217+
int expire_tiles::from_bbox(geom::box_t const &box,
218+
expire_config_t const &expire_config)
195219
{
196220
if (!enabled()) {
197221
return 0;
@@ -203,28 +227,32 @@ int expire_tiles::from_bbox(geom::box_t const &box)
203227
/* Over half the planet's width within the bounding box - assume the
204228
box crosses the international date line and split it into two boxes */
205229
int ret = from_bbox({-tile_t::half_earth_circumference, box.min_y(),
206-
box.min_x(), box.max_y()});
230+
box.min_x(), box.max_y()},
231+
expire_config);
207232
ret += from_bbox({box.max_x(), box.min_y(),
208-
tile_t::half_earth_circumference, box.max_y()});
233+
tile_t::half_earth_circumference, box.max_y()},
234+
expire_config);
209235
return ret;
210236
}
211237

212-
if (width > m_max_bbox || height > m_max_bbox) {
238+
if (expire_config.mode == expire_mode::hybrid &&
239+
(width > expire_config.full_area_limit ||
240+
height > expire_config.full_area_limit)) {
213241
return -1;
214242
}
215243

216244
/* Convert the box's Mercator coordinates into tile coordinates */
217245
auto const tmp_min = coords_to_tile({box.min_x(), box.max_y()});
218246
int const min_tile_x =
219-
std::clamp(int(tmp_min.x() - tile_expiry_leeway), 0, m_map_width);
247+
std::clamp(int(tmp_min.x() - expire_config.buffer), 0, m_map_width);
220248
int const min_tile_y =
221-
std::clamp(int(tmp_min.y() - tile_expiry_leeway), 0, m_map_width);
249+
std::clamp(int(tmp_min.y() - expire_config.buffer), 0, m_map_width);
222250

223251
auto const tmp_max = coords_to_tile({box.max_x(), box.min_y()});
224252
int const max_tile_x =
225-
std::clamp(int(tmp_max.x() + tile_expiry_leeway), 0, m_map_width);
253+
std::clamp(int(tmp_max.x() + expire_config.buffer), 0, m_map_width);
226254
int const max_tile_y =
227-
std::clamp(int(tmp_max.y() + tile_expiry_leeway), 0, m_map_width);
255+
std::clamp(int(tmp_max.y() + expire_config.buffer), 0, m_map_width);
228256

229257
for (int iterator_x = min_tile_x; iterator_x <= max_tile_x; ++iterator_x) {
230258
uint32_t const norm_x = normalise_tile_x_coord(iterator_x);
@@ -286,12 +314,13 @@ std::size_t output_tiles_to_file(quadkey_list_t const &tiles_at_maxzoom,
286314
return count;
287315
}
288316

289-
int expire_from_result(expire_tiles *expire, pg_result_t const &result)
317+
int expire_from_result(expire_tiles *expire, pg_result_t const &result,
318+
expire_config_t const &expire_config)
290319
{
291320
auto const num_tuples = result.num_tuples();
292321

293322
for (int i = 0; i < num_tuples; ++i) {
294-
expire->from_geometry(ewkb_to_geom(result.get(i, 0)));
323+
expire->from_geometry(ewkb_to_geom(result.get(i, 0)), expire_config);
295324
}
296325

297326
return num_tuples;

src/expire-tiles.hpp

Lines changed: 39 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <utility>
1717
#include <vector>
1818

19+
#include "expire-config.hpp"
1920
#include "geom.hpp"
2021
#include "geom-box.hpp"
2122
#include "logging.hpp"
@@ -28,32 +29,48 @@ class reprojection;
2829
class expire_tiles
2930
{
3031
public:
31-
expire_tiles(uint32_t max_zoom, double max_bbox,
32-
std::shared_ptr<reprojection> projection);
32+
expire_tiles(uint32_t max_zoom, std::shared_ptr<reprojection> projection);
3333

3434
bool enabled() const noexcept { return m_maxzoom != 0; }
3535

36-
void from_polygon_boundary(geom::polygon_t const &geom);
36+
void from_polygon_boundary(geom::polygon_t const &geom,
37+
expire_config_t const &expire_config);
3738

38-
void from_geometry(geom::nullgeom_t const & /*geom*/) {}
39-
void from_geometry(geom::point_t const &geom);
40-
void from_geometry(geom::linestring_t const &geom);
41-
void from_geometry(geom::polygon_t const &geom);
42-
void from_geometry(geom::multipolygon_t const &geom);
39+
void from_polygon_boundary(geom::multipolygon_t const &geom,
40+
expire_config_t const &expire_config);
41+
42+
void from_geometry(geom::nullgeom_t const & /*geom*/,
43+
expire_config_t const & /*expire_config*/)
44+
{}
45+
46+
void from_geometry(geom::point_t const &geom,
47+
expire_config_t const &expire_config);
48+
49+
void from_geometry(geom::linestring_t const &geom,
50+
expire_config_t const &expire_config);
51+
52+
void from_geometry(geom::polygon_t const &geom,
53+
expire_config_t const &expire_config);
54+
55+
void from_geometry(geom::multipolygon_t const &geom,
56+
expire_config_t const &expire_config);
4357

4458
template <typename T>
45-
void from_geometry(geom::multigeometry_t<T> const &geom)
59+
void from_geometry(geom::multigeometry_t<T> const &geom,
60+
expire_config_t const &expire_config)
4661
{
4762
for (auto const &sgeom : geom) {
48-
from_geometry(sgeom);
63+
from_geometry(sgeom, expire_config);
4964
}
5065
}
5166

52-
void from_geometry(geom::geometry_t const &geom);
67+
void from_geometry(geom::geometry_t const &geom,
68+
expire_config_t const &expire_config);
5369

54-
void from_geometry_if_3857(geom::geometry_t const &geom);
70+
void from_geometry_if_3857(geom::geometry_t const &geom,
71+
expire_config_t const &expire_config);
5572

56-
int from_bbox(geom::box_t const &box);
73+
int from_bbox(geom::box_t const &box, expire_config_t const &expire_config);
5774

5875
/**
5976
* Get tiles as a vector of quadkeys and remove them from the expire_tiles
@@ -81,10 +98,14 @@ class expire_tiles
8198
* \param y y index of the tile to be expired.
8299
*/
83100
void expire_tile(uint32_t x, uint32_t y);
101+
84102
uint32_t normalise_tile_x_coord(int x) const;
85-
void from_line(geom::point_t const &a, geom::point_t const &b);
86103

87-
void from_point_list(geom::point_list_t const &list);
104+
void from_line_segment(geom::point_t const &a, geom::point_t const &b,
105+
expire_config_t const &expire_config);
106+
107+
void from_point_list(geom::point_list_t const &list,
108+
expire_config_t const &expire_config);
88109

89110
/// This is where we collect all the expired tiles.
90111
std::unordered_set<quadkey_t> m_dirty_tiles;
@@ -94,7 +115,6 @@ class expire_tiles
94115

95116
std::shared_ptr<reprojection> m_projection;
96117

97-
double m_max_bbox;
98118
uint32_t m_maxzoom;
99119
int m_map_width;
100120

@@ -107,9 +127,11 @@ class expire_tiles
107127
* \param result Result of a database query into some table returning the
108128
* geometries. (This is usually done using the "get_wkb"
109129
* prepared statement.)
130+
* \param expire_config Configuration for expiry.
110131
* \return The number of tuples in the result or -1 if expire is disabled.
111132
*/
112-
int expire_from_result(expire_tiles *expire, pg_result_t const &result);
133+
int expire_from_result(expire_tiles *expire, pg_result_t const &result,
134+
expire_config_t const &expire_config);
113135

114136
/**
115137
* Iterate over tiles and call output function for each tile on all requested

0 commit comments

Comments
 (0)