diff --git a/include/geom.h b/include/geom.h index f946927f..5d1ad1b6 100644 --- a/include/geom.h +++ b/include/geom.h @@ -47,6 +47,10 @@ typedef boost::variant Geometry; typedef std::pair IndexValue; typedef boost::geometry::index::rtree< IndexValue, boost::geometry::index::quadratic<16> > RTree; +// A 36-bit integer can store all OSM node IDs; we represent this as 16 collections +// of 32-bit integers. +#define NODE_SHARDS 16 +typedef uint32_t ShardedNodeID; typedef uint64_t NodeID; typedef uint64_t WayID; diff --git a/include/osm_store.h b/include/osm_store.h index 2b9cdf64..912f3f8f 100644 --- a/include/osm_store.h +++ b/include/osm_store.h @@ -79,12 +79,19 @@ class NodeStore public: using element_t = std::pair; + using internal_element_t = std::pair; using map_t = std::deque>; void reopen() { std::lock_guard lock(mutex); - mLatpLons = std::make_unique(); + for (auto i = 0; i < mLatpLons.size(); i++) + mLatpLons[i]->clear(); + + mLatpLons.clear(); + for (auto i = 0; i < NODE_SHARDS; i++) { + mLatpLons.push_back(std::make_unique()); + } } // @brief Lookup a latp/lon pair @@ -92,11 +99,14 @@ class NodeStore // @return Latp/lon pair // @exception NotFound LatpLon at(NodeID i) const { - auto iter = std::lower_bound(mLatpLons->begin(), mLatpLons->end(), i, [](auto const &e, auto i) { + auto shard = mLatpLons[shardPart(i)]; + auto id = idPart(i); + + auto iter = std::lower_bound(shard->begin(), shard->end(), id, [](auto const &e, auto i) { return e.first < i; }); - if(iter == mLatpLons->end() || iter->first != i) + if(iter == shard->end() || iter->first != id) throw std::out_of_range("Could not find node with id " + std::to_string(i)); return iter->second; @@ -105,7 +115,11 @@ class NodeStore // @brief Return the number of stored items size_t size() const { std::lock_guard lock(mutex); - return mLatpLons->size(); + uint64_t size = 0; + for (auto i = 0; i < mLatpLons.size(); i++) + size += mLatpLons[i]->size(); + + return size; } // @brief Insert a latp/lon pair. @@ -114,27 +128,49 @@ class NodeStore // @invariant The OSM ID i must be larger than previously inserted OSM IDs of nodes // (though unnecessarily for current impl, future impl may impose that) void insert_back(NodeID i, LatpLon coord) { - mLatpLons->push_back(std::make_pair(i, coord)); + mLatpLons[shardPart(i)]->push_back(std::make_pair(idPart(i), coord)); } void insert_back(std::vector const &element) { + uint32_t newEntries[NODE_SHARDS] = {}; + + // Before taking the lock, do a pass to find out how much + // to grow each backing collection + for (auto it = element.begin(); it != element.end(); it++) { + newEntries[shardPart(it->first)]++; + } + std::lock_guard lock(mutex); - auto i = mLatpLons->size(); - mLatpLons->resize(i + element.size()); - std::copy(element.begin(), element.end(), mLatpLons->begin() + i); + for (auto i = 0; i < NODE_SHARDS; i++) { + if (newEntries[i] == 0) continue; + auto size = mLatpLons[i]->size(); + mLatpLons[i]->resize(size + newEntries[i]); + } + + for (auto it = element.begin(); it != element.end(); it++) { + insert_back(it->first, it->second); + } } // @brief Make the store empty void clear() { - std::lock_guard lock(mutex); - mLatpLons->clear(); + reopen(); } void sort(unsigned int threadNum); private: mutable std::mutex mutex; - std::shared_ptr mLatpLons; + std::vector> mLatpLons; + + uint32_t shardPart(NodeID id) const { + uint32_t rv = id >> 32; + return rv; + } + + uint32_t idPart(NodeID id) const { + return id; + } }; class CompactNodeStore diff --git a/src/osm_store.cpp b/src/osm_store.cpp index b9843ee4..75a6aadc 100644 --- a/src/osm_store.cpp +++ b/src/osm_store.cpp @@ -262,10 +262,12 @@ void void_mmap_allocator::destroy(void *p) void NodeStore::sort(unsigned int threadNum) { std::lock_guard lock(mutex); - boost::sort::block_indirect_sort( - mLatpLons->begin(), mLatpLons->end(), - [](auto const &a, auto const &b) { return a.first < b.first; }, - threadNum); + for (auto i = 0; i < NODE_SHARDS; i++) { + boost::sort::block_indirect_sort( + mLatpLons[i]->begin(), mLatpLons[i]->end(), + [](auto const &a, auto const &b) { return a.first < b.first; }, + threadNum); + } } void WayStore::sort(unsigned int threadNum) {