Skip to content

Commit b302bc0

Browse files
authored
Merge pull request #1168 from joto/dependency-manager
New dependency manager
2 parents 7c1bdf7 + 11deb9c commit b302bc0

15 files changed

+430
-243
lines changed

src/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11

22
set(osm2pgsql_lib_SOURCES
3+
dependency-manager.cpp
34
db-copy.cpp
45
expire-tiles.cpp
56
gazetteer-style.cpp
@@ -31,6 +32,7 @@ set(osm2pgsql_lib_SOURCES
3132
tagtransform.cpp
3233
util.cpp
3334
wildcmp.cpp
35+
dependency-manager.hpp
3436
db-copy.hpp
3537
expire-tiles.hpp
3638
gazetteer-style.hpp

src/dependency-manager.cpp

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
2+
#include "dependency-manager.hpp"
3+
4+
void full_dependency_manager_t::node_changed(osmid_t id)
5+
{
6+
for (auto const way_id : m_object_store->get_ways_by_node(id)) {
7+
way_changed(way_id);
8+
m_ways_pending_tracker.mark(way_id);
9+
}
10+
11+
for (auto const rel_id : m_object_store->get_rels_by_node(id)) {
12+
m_rels_pending_tracker.mark(rel_id);
13+
}
14+
}
15+
16+
void full_dependency_manager_t::way_changed(osmid_t id)
17+
{
18+
if (m_ways_pending_tracker.is_marked(id)) {
19+
return;
20+
}
21+
22+
for (auto const rel_id : m_object_store->get_rels_by_way(id)) {
23+
m_rels_pending_tracker.mark(rel_id);
24+
}
25+
}
26+
27+
void full_dependency_manager_t::relation_changed(osmid_t id)
28+
{
29+
for (auto const rel_id : m_object_store->get_rels_by_rel(id)) {
30+
m_rels_pending_tracker.mark(rel_id);
31+
}
32+
}
33+
34+
void full_dependency_manager_t::relation_deleted(osmid_t id)
35+
{
36+
for (auto const rel_id : m_object_store->get_ways_by_rel(id)) {
37+
m_ways_pending_tracker.mark(rel_id);
38+
}
39+
}
40+
41+
bool full_dependency_manager_t::has_pending() const noexcept
42+
{
43+
return !m_ways_pending_tracker.empty() || !m_rels_pending_tracker.empty();
44+
}
45+
46+
void full_dependency_manager_t::process_pending(pending_processor &proc)
47+
{
48+
osmid_t id;
49+
while (id_tracker::is_valid(id = m_ways_pending_tracker.pop_mark())) {
50+
proc.enqueue_way(id);
51+
}
52+
53+
proc.process_ways();
54+
55+
while (id_tracker::is_valid(id = m_rels_pending_tracker.pop_mark())) {
56+
proc.enqueue_relation(id);
57+
}
58+
59+
proc.process_relations();
60+
}

src/dependency-manager.hpp

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
#ifndef OSM2PGSQL_DEPENDENCY_MANAGER_HPP
2+
#define OSM2PGSQL_DEPENDENCY_MANAGER_HPP
3+
4+
#include "id-tracker.hpp"
5+
#include "middle.hpp"
6+
#include "osmtypes.hpp"
7+
8+
#include <cassert>
9+
#include <memory>
10+
11+
struct pending_processor
12+
{
13+
virtual ~pending_processor() = default;
14+
15+
virtual void enqueue_way(osmid_t id) = 0;
16+
virtual void enqueue_relation(osmid_t id) = 0;
17+
18+
virtual void process_ways() = 0;
19+
virtual void process_relations() = 0;
20+
};
21+
22+
/**
23+
* The job of the dependency manager is to keep track of the dependencies
24+
* between OSM objects, that is nodes in ways and members of relations.
25+
*
26+
* Whenever an OSM object changes, this class is notified and can remember
27+
* the ids for later use.
28+
*
29+
* This base class doesn't actually do the dependency management but is a
30+
* dummy for cases where no dependency management is needed. See the
31+
* full_dependency_manager_t class for the real dependency manager.
32+
*/
33+
class dependency_manager_t
34+
{
35+
public:
36+
virtual ~dependency_manager_t() = default;
37+
38+
/**
39+
* Mark a node as changed to trigger the propagation of this change to
40+
* ways and relations.
41+
*
42+
* This has to be called *after* the object was stored in the object store.
43+
*/
44+
virtual void node_changed(osmid_t) {}
45+
46+
/**
47+
* Mark a way as changed to trigger the propagation of this change to
48+
* relations.
49+
*
50+
* This has to be called *after* the object was stored in the object store.
51+
*/
52+
virtual void way_changed(osmid_t) {}
53+
54+
/**
55+
* Mark a relation as changed to trigger the propagation of this change to
56+
* other relations.
57+
*
58+
* This has to be called *after* the object was stored in the object store.
59+
*/
60+
virtual void relation_changed(osmid_t) {}
61+
62+
/**
63+
* Mark a relation as deleted to trigger the propagation of this change to
64+
* the way members.
65+
*/
66+
virtual void relation_deleted(osmid_t) {}
67+
68+
/// Are there pending objects that need to be processed?
69+
virtual bool has_pending() const noexcept { return false; }
70+
71+
/**
72+
* Process all pending objects.
73+
*
74+
* \param pf Processor that we should feed the objects to and that
75+
* will handle the actual processing.
76+
*
77+
* \post !has_pending()
78+
*/
79+
virtual void process_pending(pending_processor &) {}
80+
};
81+
82+
/**
83+
* The job of the dependency manager is to keep track of the dependencies
84+
* between OSM objects, that is nodes in ways and members of relations.
85+
*
86+
* Whenever an OSM object changes, this class is notified and remembers
87+
* the ids for later use. Later on the class can be told to process the
88+
* ids it has remembered.
89+
*/
90+
class full_dependency_manager_t : public dependency_manager_t
91+
{
92+
public:
93+
/**
94+
* Constructor.
95+
*
96+
* \param object_store Pointer to the middle that keeps the actual
97+
* database of objects and their relationsships.
98+
*
99+
* \pre object_store != nullptr
100+
*/
101+
explicit full_dependency_manager_t(std::shared_ptr<middle_t> object_store)
102+
: m_object_store(std::move(object_store))
103+
{
104+
assert(m_object_store != nullptr);
105+
}
106+
107+
void node_changed(osmid_t id) override;
108+
void way_changed(osmid_t id) override;
109+
void relation_changed(osmid_t id) override;
110+
void relation_deleted(osmid_t id) override;
111+
112+
bool has_pending() const noexcept override;
113+
114+
void process_pending(pending_processor &proc) override;
115+
116+
/**
117+
* Get access to the pending way ids. This is for debugging only.
118+
*
119+
* Note that the list of pending way ids will be empty after calling
120+
* this.
121+
*
122+
* \tparam TOutputIterator Some output iterator type, for instance
123+
* created with std::back_inserter(some vector).
124+
* \param it output iterator to which all ids should be written. *it
125+
* must be of type osmid_t.
126+
*/
127+
template <typename TOutputIterator>
128+
void get_pending_way_ids(TOutputIterator &&it)
129+
{
130+
osmid_t id;
131+
while (id_tracker::is_valid(id = m_ways_pending_tracker.pop_mark())) {
132+
*it++ = id;
133+
}
134+
}
135+
136+
/**
137+
* Get access to the pending relation ids. This is for debugging only.
138+
*
139+
* Note that the list of pending relation ids will be empty after calling
140+
* this.
141+
*
142+
* \tparam TOutputIterator Some output iterator type, for instance
143+
* created with std::back_inserter(some vector).
144+
* \param it output iterator to which all ids should be written. *it
145+
* must be of type osmid_t.
146+
*/
147+
template <typename TOutputIterator>
148+
void get_pending_relation_ids(TOutputIterator &&it)
149+
{
150+
osmid_t id;
151+
while (id_tracker::is_valid(id = m_rels_pending_tracker.pop_mark())) {
152+
*it++ = id;
153+
}
154+
}
155+
156+
private:
157+
std::shared_ptr<middle_t> m_object_store;
158+
159+
id_tracker m_ways_pending_tracker;
160+
id_tracker m_rels_pending_tracker;
161+
};
162+
163+
#endif // OSM2PGSQL_DEPENDENCY_MANAGER_HPP

src/middle-pgsql.cpp

Lines changed: 31 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@
1919
#include <osmium/memory/buffer.hpp>
2020
#include <osmium/osm/types_from_string.hpp>
2121

22-
#include <libpq-fe.h>
23-
2422
#include "format.hpp"
2523
#include "middle-pgsql.hpp"
2624
#include "node-persistent-cache.hpp"
@@ -308,25 +306,40 @@ void middle_pgsql_t::node_delete(osmid_t osm_id)
308306
}
309307
}
310308

311-
void middle_pgsql_t::node_changed(osmid_t osm_id)
309+
idlist_t middle_pgsql_t::get_ids(const char* stmt, osmid_t osm_id)
312310
{
313-
assert(m_append);
314-
if (!m_mark_pending) {
315-
return;
316-
}
311+
idlist_t ids;
317312

318-
// Find all ways referencing this node and mark them as pending.
319-
auto const res_ways =
320-
m_db_connection.exec_prepared("mark_ways_by_node", osm_id);
321-
for_each_id(res_ways, [this](osmid_t id) {
322-
way_changed(id);
323-
m_ways_pending_tracker->mark(id);
324-
});
313+
auto const res = m_db_connection.exec_prepared(stmt, osm_id);
314+
ids.reserve(res.num_tuples());
315+
for_each_id(res, [&ids](osmid_t id) { ids.push_back(id); });
316+
317+
return ids;
318+
}
319+
320+
idlist_t middle_pgsql_t::get_ways_by_node(osmid_t osm_id)
321+
{
322+
return get_ids("mark_ways_by_node", osm_id);
323+
}
324+
325+
idlist_t middle_pgsql_t::get_rels_by_node(osmid_t osm_id)
326+
{
327+
return get_ids("mark_rels_by_node", osm_id);
328+
}
329+
330+
idlist_t middle_pgsql_t::get_rels_by_way(osmid_t osm_id)
331+
{
332+
return get_ids("mark_rels_by_way", osm_id);
333+
}
334+
335+
idlist_t middle_pgsql_t::get_rels_by_rel(osmid_t osm_id)
336+
{
337+
return get_ids("mark_rels", osm_id);
338+
}
325339

326-
// Find all relations referencing this node and mark them as pending.
327-
auto const res_rels = m_db_connection.exec_prepared("mark_rels_by_node", osm_id);
328-
for_each_id(res_rels,
329-
[this](osmid_t id) { m_rels_pending_tracker->mark(id); });
340+
idlist_t middle_pgsql_t::get_ways_by_rel(osmid_t osm_id)
341+
{
342+
return get_ids("mark_ways_by_rel", osm_id);
330343
}
331344

332345
void middle_pgsql_t::way_set(osmium::Way const &way)
@@ -431,31 +444,6 @@ void middle_pgsql_t::way_delete(osmid_t osm_id)
431444
m_db_copy.delete_object(osm_id);
432445
}
433446

434-
void middle_pgsql_t::iterate_ways(pending_processor &pf)
435-
{
436-
// enqueue the jobs
437-
osmid_t id;
438-
while (id_tracker::is_valid(id = m_ways_pending_tracker->pop_mark())) {
439-
pf.enqueue_ways(id);
440-
}
441-
442-
//let the threads work on them
443-
pf.process_ways();
444-
}
445-
446-
void middle_pgsql_t::way_changed(osmid_t osm_id)
447-
{
448-
assert(m_append);
449-
450-
if (m_ways_pending_tracker->is_marked(osm_id)) {
451-
return;
452-
}
453-
454-
// Keep track of all relations having this way as member.
455-
auto const res = m_db_connection.exec_prepared("mark_rels_by_way", osm_id);
456-
for_each_id(res, [this](osmid_t id) { m_rels_pending_tracker->mark(id); });
457-
}
458-
459447
void middle_pgsql_t::relation_set(osmium::Relation const &rel)
460448
{
461449
// Sort relation members by their type.
@@ -526,34 +514,10 @@ void middle_pgsql_t::relation_delete(osmid_t osm_id)
526514
{
527515
assert(m_append);
528516

529-
// Keep track of all member ways.
530-
auto const res = m_db_connection.exec_prepared("mark_ways_by_rel", osm_id);
531-
for_each_id(res, [this](osmid_t id) { m_ways_pending_tracker->mark(id); });
532-
533517
m_db_copy.new_line(m_tables[REL_TABLE].m_copy_target);
534518
m_db_copy.delete_object(osm_id);
535519
}
536520

537-
void middle_pgsql_t::iterate_relations(pending_processor &pf)
538-
{
539-
// enqueue the jobs
540-
osmid_t id;
541-
while (id_tracker::is_valid(id = m_rels_pending_tracker->pop_mark())) {
542-
pf.enqueue_relations(id);
543-
}
544-
545-
//let the threads work on them
546-
pf.process_relations();
547-
}
548-
549-
void middle_pgsql_t::relation_changed(osmid_t osm_id)
550-
{
551-
assert(m_append);
552-
553-
auto const res = m_db_connection.exec_prepared("mark_rels", osm_id);
554-
for_each_id(res, [this](osmid_t id) { m_rels_pending_tracker->mark(id); });
555-
}
556-
557521
idlist_t middle_query_pgsql_t::relations_using_way(osmid_t way_id) const
558522
{
559523
auto const result = m_sql_conn.exec_prepared("rels_using_way", way_id);
@@ -579,9 +543,6 @@ middle_query_pgsql_t::middle_query_pgsql_t(
579543

580544
void middle_pgsql_t::start()
581545
{
582-
m_ways_pending_tracker.reset(new id_tracker{});
583-
m_rels_pending_tracker.reset(new id_tracker{});
584-
585546
// Gazetter doesn't use mark-pending processing and consequently
586547
// needs no way-node index.
587548
// TODO Currently, set here to keep the impact on the code small.
@@ -782,8 +743,3 @@ middle_pgsql_t::get_query_instance()
782743

783744
return std::shared_ptr<middle_query_t>(mid.release());
784745
}
785-
786-
bool middle_pgsql_t::has_pending() const
787-
{
788-
return !m_ways_pending_tracker->empty() || !m_rels_pending_tracker->empty();
789-
}

0 commit comments

Comments
 (0)