Skip to content

Commit 8ce9bbe

Browse files
committed
Improved node location store without need for freeze()
Store ids and locations as they come in without going through a temporary block first. Slightly simpler code and we don't need the freeze() function any more. See also #1466.
1 parent db6d89d commit 8ce9bbe

File tree

5 files changed

+39
-89
lines changed

5 files changed

+39
-89
lines changed

src/middle-ram.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -184,8 +184,6 @@ void middle_ram_t::relation(osmium::Relation const &relation)
184184
}
185185
}
186186

187-
void middle_ram_t::after_nodes() { m_node_locations.freeze(); }
188-
189187
std::size_t middle_ram_t::nodes_get_list(osmium::WayNodeList *nodes) const
190188
{
191189
assert(nodes);

src/middle-ram.hpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,6 @@ class middle_ram_t : public middle_t, public middle_query_t
5252
void way(osmium::Way const &way) override;
5353
void relation(osmium::Relation const &) override;
5454

55-
void after_nodes() override;
56-
5755
std::size_t nodes_get_list(osmium::WayNodeList *nodes) const override;
5856

5957
bool way_get(osmid_t id, osmium::memory::Buffer *buffer) const override;

src/node-locations.cpp

Lines changed: 24 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
#include "node-locations.hpp"
1111

1212
#include <osmium/osm/location.hpp>
13-
#include <osmium/util/delta.hpp>
1413

1514
// Workaround: This must be included before buffer_string.hpp due to a missing
1615
// include in the upstream code. https://github.com/mapbox/protozero/pull/104
@@ -24,13 +23,20 @@
2423

2524
void node_locations_t::set(osmid_t id, osmium::Location location)
2625
{
27-
assert(block_index() == 0 || m_block[block_index() - 1].first < id);
26+
if (first_entry_in_block()) {
27+
m_did.clear();
28+
m_dx.clear();
29+
m_dy.clear();
30+
m_index.add(id, m_data.size());
31+
}
32+
33+
protozero::add_varint_to_buffer(&m_data, m_did.update(id));
34+
protozero::add_varint_to_buffer(
35+
&m_data, protozero::encode_zigzag64(m_dx.update(location.x())));
36+
protozero::add_varint_to_buffer(
37+
&m_data, protozero::encode_zigzag64(m_dy.update(location.y())));
2838

29-
m_block[block_index()] = {id, location};
3039
++m_count;
31-
if (block_index() == 0) {
32-
freeze();
33-
}
3440
}
3541

3642
osmium::Location node_locations_t::get(osmid_t id) const
@@ -46,72 +52,29 @@ osmium::Location node_locations_t::get(osmid_t id) const
4652
char const *const end = m_data.data() + m_data.size();
4753

4854
osmium::DeltaDecode<osmid_t> did;
49-
std::size_t num = block_size;
50-
for (std::size_t n = 0; n < block_size; ++n) {
51-
auto bid = did.update(protozero::decode_varint(&begin, end));
52-
if (bid == id) {
53-
num = n;
54-
}
55-
if (bid > id && num == block_size) {
56-
return osmium::Location{};
57-
}
58-
}
59-
if (num == block_size) {
60-
return osmium::Location{};
61-
}
62-
6355
osmium::DeltaDecode<int64_t> dx;
6456
osmium::DeltaDecode<int64_t> dy;
65-
int32_t x = 0;
66-
int32_t y = 0;
67-
for (std::size_t n = 0; n <= num; ++n) {
68-
x = dx.update(
57+
58+
for (std::size_t n = 0; n < block_size && begin != end; ++n) {
59+
auto const bid = did.update(protozero::decode_varint(&begin, end));
60+
int32_t const x = dx.update(
6961
protozero::decode_zigzag64(protozero::decode_varint(&begin, end)));
70-
y = dy.update(
62+
int32_t const y = dy.update(
7163
protozero::decode_zigzag64(protozero::decode_varint(&begin, end)));
64+
if (bid == id) {
65+
return osmium::Location{x, y};
66+
}
67+
if (bid > id) {
68+
break;
69+
}
7270
}
73-
74-
return osmium::Location{x, y};
75-
}
76-
77-
void node_locations_t::freeze()
78-
{
79-
encode_block();
80-
clear_block();
71+
return osmium::Location{};
8172
}
8273

8374
void node_locations_t::clear()
8475
{
8576
m_data.clear();
8677
m_data.shrink_to_fit();
8778
m_index.clear();
88-
clear_block();
8979
m_count = 0;
9080
}
91-
92-
void node_locations_t::encode_block()
93-
{
94-
auto const offset = m_data.size();
95-
osmium::DeltaEncode<osmid_t> did;
96-
osmium::DeltaEncode<int64_t> dx;
97-
osmium::DeltaEncode<int64_t> dy;
98-
for (auto const &nl : m_block) {
99-
protozero::add_varint_to_buffer(&m_data, did.update(nl.first));
100-
}
101-
for (auto const &nl : m_block) {
102-
protozero::add_varint_to_buffer(
103-
&m_data, protozero::encode_zigzag64(dx.update(nl.second.x())));
104-
protozero::add_varint_to_buffer(
105-
&m_data, protozero::encode_zigzag64(dy.update(nl.second.y())));
106-
}
107-
m_index.add(m_block[0].first, offset);
108-
}
109-
110-
void node_locations_t::clear_block()
111-
{
112-
for (auto &nl : m_block) {
113-
nl.first = std::numeric_limits<osmid_t>::max();
114-
nl.second = osmium::Location{};
115-
}
116-
}
117-

src/node-locations.hpp

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
#include "ordered-index.hpp"
1414
#include "osmtypes.hpp"
1515

16+
#include <osmium/util/delta.hpp>
17+
1618
#include <array>
1719
#include <cstddef>
1820
#include <string>
@@ -25,18 +27,14 @@
2527
*
2628
* Internally nodes are stored in blocks of `block_size` (id, location) pairs.
2729
* Ids inside a block and the x and y coordinates of each location are first
28-
* delta encoded and then stored as varints. To access a stored location a
29-
* full block must be decoded.
30+
* delta encoded and then stored as varints. To access a stored location the
31+
* block must be decoded until the id is found.
3032
*
31-
* Ids must be added in strictly ascending order. After all ids are stored,
32-
* the `freeze()` function must be called. Only after that can the store
33-
* be queried.
33+
* Ids must be added in strictly ascending order.
3434
*/
3535
class node_locations_t
3636
{
3737
public:
38-
node_locations_t() { clear_block(); }
39-
4038
/**
4139
* Store a node location.
4240
*
@@ -60,35 +58,32 @@ class node_locations_t
6058
}
6159

6260
/**
63-
* Freeze storage. Muste be called after set()ing all the ids and before
64-
* get()ing the first one.
65-
*/
66-
void freeze();
67-
68-
/**
69-
* Clear the memory used by this object. The object can not be reused
70-
* after that.
61+
* Clear the memory used by this object. The object can be reused after
62+
* that.
7163
*/
7264
void clear();
7365

7466
private:
75-
std::size_t block_index() const noexcept { return m_count % block_size; }
76-
77-
void encode_block();
78-
void clear_block();
67+
bool first_entry_in_block() const noexcept
68+
{
69+
return m_count % block_size == 0;
70+
}
7971

8072
/**
8173
* The block size used for internal blocks. The larger the block size
8274
* the less memory is consumed but the more expensive the access is.
8375
*/
8476
static constexpr const std::size_t block_size = 32;
8577

86-
std::array<std::pair<osmid_t, osmium::Location>, block_size> m_block;
8778
ordered_index_t m_index;
8879
std::string m_data;
8980

9081
/// The number of (id, location) pairs stored.
9182
std::size_t m_count = 0;
83+
84+
osmium::DeltaEncode<osmid_t> m_did;
85+
osmium::DeltaEncode<int64_t> m_dx;
86+
osmium::DeltaEncode<int64_t> m_dy;
9287
}; // class node_locations_t
9388

9489
#endif // OSM2PGSQL_NODE_LOCATIONS_HPP

tests/test-node-locations.cpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,6 @@ TEST_CASE("node locations basics", "[NoDB]")
2121

2222
REQUIRE(nl.size() == 2);
2323

24-
nl.freeze();
25-
REQUIRE(nl.size() == 2);
26-
2724
REQUIRE(nl.get(1) == osmium::Location{});
2825
REQUIRE(nl.get(4) == osmium::Location{});
2926
REQUIRE(nl.get(6) == osmium::Location{});
@@ -70,7 +67,6 @@ TEST_CASE("node locations in more than one block", "[NoDB]")
7067
nl.set(id, {id + 0.1, id + 0.2});
7168
}
7269

73-
nl.freeze();
7470
REQUIRE(nl.size() == max_id);
7571

7672
for (std::size_t id = 1; id <= max_id; ++id) {

0 commit comments

Comments
 (0)