Skip to content

Commit e67dc95

Browse files
committed
Add and use expire_config_t struct
This commit introduces a new struct expire_config_t which collects some configuration options for expire. All functions that calculate which tiles to expire from some geometry now get an instance of this struct as parameter. Config parameters are: * `buffer` decides how far around the actual geometries the tiles should be expired. This replaces the "tile_expiry_leeway" constant. It is always set to 0.1 (= 10% of tile size) as before and can currently not be changed. * `mode` is a new enum setting. It can be "full_area", "boundary_only", or "hybrid". Currently always set to "full_area" or "hybrid" based on `--expire-bbox-size` for backwards compatibility and can not be changed. * `full_area_limit` used to be a setting "max_bbox" in the expire_tiles class. It is set by the `--expire-bbox-size=SIZE` option. It specifies the max width and height for a polygon bbox to expire the whole bbox of the polygon, not just the boundary (default 20000). From here on the expire_tiles class is only responsible for actually keeping a list of expired tiles while the config which tiles are to be expired is added dynamically when the actual expiry happens. This will allow us in the future to have different layers with different expiry options feed into the same expired tile list.
1 parent 1bad5da commit e67dc95

11 files changed

+301
-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: 69 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,93 @@ 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(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(geom::point_t const &a, geom::point_t const &b,
157+
expire_config_t const &expire_config)
136158
{
137159
auto tilec_a = coords_to_tile(a);
138160
auto tilec_b = coords_to_tile(b);
@@ -175,11 +197,11 @@ void expire_tiles::from_line(geom::point_t const &a, geom::point_t const &b)
175197
if (y1 > y2) {
176198
std::swap(y1, y2);
177199
}
178-
for (int x = x1 - tile_expiry_leeway; x <= x2 + tile_expiry_leeway;
200+
for (int x = x1 - expire_config.buffer; x <= x2 + expire_config.buffer;
179201
++x) {
180202
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) {
203+
for (int y = y1 - expire_config.buffer;
204+
y <= y2 + expire_config.buffer; ++y) {
183205
if (y >= 0) {
184206
expire_tile(norm_x, static_cast<uint32_t>(y));
185207
}
@@ -191,7 +213,8 @@ void expire_tiles::from_line(geom::point_t const &a, geom::point_t const &b)
191213
/*
192214
* Expire tiles within a bounding box
193215
*/
194-
int expire_tiles::from_bbox(geom::box_t const &box)
216+
int expire_tiles::from_bbox(geom::box_t const &box,
217+
expire_config_t const &expire_config)
195218
{
196219
if (!enabled()) {
197220
return 0;
@@ -203,28 +226,32 @@ int expire_tiles::from_bbox(geom::box_t const &box)
203226
/* Over half the planet's width within the bounding box - assume the
204227
box crosses the international date line and split it into two boxes */
205228
int ret = from_bbox({-tile_t::half_earth_circumference, box.min_y(),
206-
box.min_x(), box.max_y()});
229+
box.min_x(), box.max_y()},
230+
expire_config);
207231
ret += from_bbox({box.max_x(), box.min_y(),
208-
tile_t::half_earth_circumference, box.max_y()});
232+
tile_t::half_earth_circumference, box.max_y()},
233+
expire_config);
209234
return ret;
210235
}
211236

212-
if (width > m_max_bbox || height > m_max_bbox) {
237+
if (expire_config.mode == expire_mode::hybrid &&
238+
(width > expire_config.full_area_limit ||
239+
height > expire_config.full_area_limit)) {
213240
return -1;
214241
}
215242

216243
/* Convert the box's Mercator coordinates into tile coordinates */
217244
auto const tmp_min = coords_to_tile({box.min_x(), box.max_y()});
218245
int const min_tile_x =
219-
std::clamp(int(tmp_min.x() - tile_expiry_leeway), 0, m_map_width);
246+
std::clamp(int(tmp_min.x() - expire_config.buffer), 0, m_map_width);
220247
int const min_tile_y =
221-
std::clamp(int(tmp_min.y() - tile_expiry_leeway), 0, m_map_width);
248+
std::clamp(int(tmp_min.y() - expire_config.buffer), 0, m_map_width);
222249

223250
auto const tmp_max = coords_to_tile({box.max_x(), box.min_y()});
224251
int const max_tile_x =
225-
std::clamp(int(tmp_max.x() + tile_expiry_leeway), 0, m_map_width);
252+
std::clamp(int(tmp_max.x() + expire_config.buffer), 0, m_map_width);
226253
int const max_tile_y =
227-
std::clamp(int(tmp_max.y() + tile_expiry_leeway), 0, m_map_width);
254+
std::clamp(int(tmp_max.y() + expire_config.buffer), 0, m_map_width);
228255

229256
for (int iterator_x = min_tile_x; iterator_x <= max_tile_x; ++iterator_x) {
230257
uint32_t const norm_x = normalise_tile_x_coord(iterator_x);
@@ -286,12 +313,13 @@ std::size_t output_tiles_to_file(quadkey_list_t const &tiles_at_maxzoom,
286313
return count;
287314
}
288315

289-
int expire_from_result(expire_tiles *expire, pg_result_t const &result)
316+
int expire_from_result(expire_tiles *expire, pg_result_t const &result,
317+
expire_config_t const &expire_config)
290318
{
291319
auto const num_tuples = result.num_tuples();
292320

293321
for (int i = 0; i < num_tuples; ++i) {
294-
expire->from_geometry(ewkb_to_geom(result.get(i, 0)));
322+
expire->from_geometry(ewkb_to_geom(result.get(i, 0)), expire_config);
295323
}
296324

297325
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(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)