diff --git a/coding/coding_tests/var_record_reader_test.cpp b/coding/coding_tests/var_record_reader_test.cpp index b32e7aa5e16..b0d6992b453 100644 --- a/coding/coding_tests/var_record_reader_test.cpp +++ b/coding/coding_tests/var_record_reader_test.cpp @@ -52,13 +52,13 @@ UNIT_TEST(VarRecordReader_Simple) MemReader reader(&data[0], data.size()); VarRecordReader recordReader(reader); - auto r = recordReader.ReadRecord(0); + auto r = recordReader.ReadRecord(0, 0); TEST_EQUAL(string(r.begin(), r.end()), "abc", ()); - r = recordReader.ReadRecord(6 + longStringSize); + r = recordReader.ReadRecord(6 + longStringSize, 0); TEST_EQUAL(string(r.begin(), r.end()), "defg", ()); - r = recordReader.ReadRecord(4); + r = recordReader.ReadRecord(4, 0); TEST_EQUAL(string(r.begin(), r.end()), longString, ()); vector> forEachCalls; diff --git a/coding/file_reader.cpp b/coding/file_reader.cpp index 1966935e1e9..f328643496f 100644 --- a/coding/file_reader.cpp +++ b/coding/file_reader.cpp @@ -57,6 +57,7 @@ class FileReader::FileReaderData uint64_t Size() const { return m_fileData.Size(); } +// std::mutex mut; void Read(uint64_t pos, void * p, size_t size) { #if LOG_FILE_READER_STATS @@ -65,7 +66,8 @@ class FileReader::FileReaderData LOG(LINFO, ("FileReader", m_fileData.GetName(), m_readerCache.GetStatsStr())); } #endif - + // TODO This cache should not be accessed from different threads. +// std::lock_guard guard(mut); return m_readerCache.Read(m_fileData, pos, p, size); } diff --git a/coding/var_record_reader.hpp b/coding/var_record_reader.hpp index dbbd388d8d1..f003b9c8ea1 100644 --- a/coding/var_record_reader.hpp +++ b/coding/var_record_reader.hpp @@ -1,5 +1,7 @@ #pragma once +#include "indexer/feature.hpp" + #include "coding/byte_stream.hpp" #include "coding/reader.hpp" #include "coding/varint.hpp" @@ -18,7 +20,7 @@ class VarRecordReader public: VarRecordReader(ReaderT const & reader) : m_reader(reader) {} - std::vector ReadRecord(uint64_t const pos) const + std::vector ReadRecord(uint64_t const pos, uint32_t index) const { ReaderSource source(m_reader); ASSERT_LESS(pos, source.Size(), ()); @@ -26,6 +28,7 @@ class VarRecordReader uint32_t const recordSize = ReadVarUint(source); std::vector buffer(recordSize); source.Read(buffer.data(), recordSize); + CheckFeatureTypeData(buffer, pos, index, recordSize); return buffer; } diff --git a/data/countries.txt b/data/countries.txt index 048435d51ec..e1b5e56026d 100644 --- a/data/countries.txt +++ b/data/countries.txt @@ -1,5 +1,5 @@ { - "v": 200607, + "v": 200920, "id": "Countries", "g": [ { diff --git a/generator/generator_tests_support/routing_helpers.hpp b/generator/generator_tests_support/routing_helpers.hpp index bc5387d0704..10ded47d619 100644 --- a/generator/generator_tests_support/routing_helpers.hpp +++ b/generator/generator_tests_support/routing_helpers.hpp @@ -31,7 +31,7 @@ class TestGeometryLoader : public GeometryLoader { public: // GeometryLoader overrides: - void Load(uint32_t featureId, routing::RoadGeometry & road) override; + void Load(uint32_t featureId, bool isOutgoing, routing::RoadGeometry & road) override; void AddRoad(uint32_t featureId, bool oneWay, float speed, routing::RoadGeometry::Points const & points); diff --git a/generator/restriction_collector.cpp b/generator/restriction_collector.cpp index d02c02b4bae..3cc404fe3f0 100644 --- a/generator/restriction_collector.cpp +++ b/generator/restriction_collector.cpp @@ -129,8 +129,8 @@ bool RestrictionCollector::ParseRestrictions(std::string const & path) Joint::Id RestrictionCollector::GetFirstCommonJoint(uint32_t firstFeatureId, uint32_t secondFeatureId) const { - uint32_t const firstLen = m_indexGraph->GetGeometry().GetRoad(firstFeatureId).GetPointsCount(); - uint32_t const secondLen = m_indexGraph->GetGeometry().GetRoad(secondFeatureId).GetPointsCount(); + uint32_t const firstLen = m_indexGraph->GetGeometry().GetRoad(firstFeatureId, true /* isOutgoing */).GetPointsCount(); + uint32_t const secondLen = m_indexGraph->GetGeometry().GetRoad(secondFeatureId, true /* isOutgoing */).GetPointsCount(); auto const firstRoad = m_indexGraph->GetRoad(firstFeatureId); auto const secondRoad = m_indexGraph->GetRoad(secondFeatureId); @@ -155,7 +155,7 @@ bool RestrictionCollector::FeatureHasPointWithCoords(uint32_t featureId, m2::PointD const & coords) const { CHECK(m_indexGraph, ()); - auto const & roadGeometry = m_indexGraph->GetGeometry().GetRoad(featureId); + auto const & roadGeometry = m_indexGraph->GetGeometry().GetRoad(featureId, true /* isOutgoing */); uint32_t const pointsCount = roadGeometry.GetPointsCount(); for (uint32_t i = 0; i < pointsCount; ++i) { @@ -245,7 +245,7 @@ bool RestrictionCollector::CheckAndProcessUTurn(Restriction::Type & restrictionT uint32_t & featureId = featureIds.back(); - auto const & road = m_indexGraph->GetGeometry().GetRoad(featureId); + auto const & road = m_indexGraph->GetGeometry().GetRoad(featureId, true /* isOutgoing */); // Can not do UTurn from feature to the same feature if it is one way. if (road.IsOneWay()) return false; diff --git a/generator/routing_index_generator.cpp b/generator/routing_index_generator.cpp index ffd1b1e8696..31cd034e461 100644 --- a/generator/routing_index_generator.cpp +++ b/generator/routing_index_generator.cpp @@ -173,7 +173,7 @@ class IndexGraphWrapper final routing::Segment GetFinishSegment() const { return {}; } bool ConvertToReal(routing::Segment const & /* segment */) const { return false; } routing::RouteWeight HeuristicCostEstimate(routing::Segment const & /* from */, - ms::LatLon const & /* to */) + ms::LatLon const & /* to */, bool) { CHECK(false, ("This method exists only for compatibility with IndexGraphStarterJoints")); return routing::GetAStarWeightZero(); @@ -202,9 +202,9 @@ class IndexGraphWrapper final routing::RouteWeight GetAStarWeightEpsilon() { return routing::RouteWeight(0.0); } // @} - ms::LatLon const & GetPoint(routing::Segment const & s, bool forward) + ms::LatLon const & GetPoint(routing::Segment const & s, bool forward, bool isOutgoing) { - return m_graph.GetPoint(s, forward); + return m_graph.GetPoint(s, forward, isOutgoing); } void GetEdgesList(routing::Segment const & child, bool isOutgoing, @@ -234,7 +234,7 @@ class IndexGraphWrapper final } template - routing::RouteWeight HeuristicCostEstimate(Vertex const & /* from */, m2::PointD const & /* to */) + routing::RouteWeight HeuristicCostEstimate(Vertex const & /* from */, m2::PointD const & /* to */, bool) { CHECK(false, ("This method should not be use, it is just for compatibility with " "IndexGraphStarterJoints.")); @@ -256,7 +256,7 @@ class DijkstraWrapperJoints : public routing::IndexGraphStarterJoints(); } diff --git a/indexer/classificator.hpp b/indexer/classificator.hpp index 471cec8c032..138881465fd 100644 --- a/indexer/classificator.hpp +++ b/indexer/classificator.hpp @@ -185,6 +185,7 @@ class Classificator uint32_t GetIndexForType(uint32_t t) const { return m_mapping.GetIndex(t); } // Throws std::out_of_range exception. uint32_t GetTypeForIndex(uint32_t i) const { return m_mapping.GetType(i); } + bool IsIndexOk(uint32_t ind) const { return m_mapping.IsIndexOk(ind); } bool IsTypeValid(uint32_t t) const { return m_mapping.HasIndex(t); } inline uint32_t GetCoastType() const { return m_coastType; } diff --git a/indexer/data_source.cpp b/indexer/data_source.cpp index 84b10e19ce7..0f7eb5d49ad 100644 --- a/indexer/data_source.cpp +++ b/indexer/data_source.cpp @@ -134,6 +134,7 @@ unique_ptr FeaturesLoaderGuard::GetOriginalOrEditedFeatureByIndex(u unique_ptr FeaturesLoaderGuard::GetFeatureByIndex(uint32_t index) const { + CHECK(m_handle.IsAlive(), ()); if (!m_handle.IsAlive()) return {}; @@ -149,6 +150,7 @@ unique_ptr FeaturesLoaderGuard::GetFeatureByIndex(uint32_t index) c unique_ptr FeaturesLoaderGuard::GetOriginalFeatureByIndex(uint32_t index) const { + CHECK(m_handle.IsAlive(), ()); return m_handle.IsAlive() ? m_source->GetOriginalFeature(index) : nullptr; } diff --git a/indexer/feature.cpp b/indexer/feature.cpp index 9aba8e23dd8..74a50d9cd59 100644 --- a/indexer/feature.cpp +++ b/indexer/feature.cpp @@ -196,6 +196,13 @@ FeatureType::FeatureType(SharedLoadInfo const * loadInfo, vector && buf m_header = Header(m_data); } +FeatureType::FeatureType(feature::SharedLoadInfo const * loadInfo, std::vector && buffer, + feature::MetadataIndex const * metadataIndex, uint32_t offset) + : FeatureType(loadInfo, std::move(buffer), metadataIndex) +{ + m_offset = offset; +} + FeatureType::FeatureType(osm::MapObject const & emo) { HeaderGeomType headerGeomType = HeaderGeomType::Point; @@ -275,19 +282,22 @@ void FeatureType::ParseTypes() size_t const count = GetTypesCount(); uint32_t index = 0; + uint32_t type = 0; + size_t i = 0; try { - for (size_t i = 0; i < count; ++i) + for (i = 0; i < count; ++i) { index = ReadVarUint(source); - m_types[i] = c.GetTypeForIndex(index); + type = c.GetTypeForIndex(index); + m_types[i] = type; } } catch (std::out_of_range const & ex) { LOG(LERROR, ("Incorrect type index for feature.FeatureID:", m_id, ". Incorrect index:", index, ". Loaded feature types:", m_types, ". Total count of types:", count, - ". Header:", m_header)); + ". Header:", m_header, "type:", type, "ex:", ex.what(), "i:", i)); throw; } @@ -815,3 +825,41 @@ feature::Metadata & FeatureType::GetMetadata() ParseMetadata(); return m_metadata; } + +void CheckFeatureTypeData(std::vector const & data, uint64_t offset, uint32_t fid, + uint32_t recordSize) +{ + static std::atomic counter = 0; + ++counter; + CHECK(!data.empty(), ("offset:", offset, "fid:", fid, "counter:", counter, "recordSize:", recordSize)); + + auto const header = data[0]; + auto const typesOffset = sizeof(header); + Classificator & c = classif(); + ArrayByteSource source(data.data() + typesOffset); + + size_t const count = (header & feature::HEADER_MASK_TYPE) + 1; + uint32_t index = 0; + uint32_t type = 0; + size_t i = 0; + try + { + for (i = 0; i < count; ++i) + { + index = ReadVarUint(source); + type = c.GetTypeForIndex(index); + } + } + catch (std::out_of_range const & ex) + { + LOG(LCRITICAL, ("Incorrect type index:", index, ". header:", header, ". Size of data:", data, + ". count:", count, "type:", type, "ex:", ex.what(), "i:", i, + "Is index ok:", c.IsIndexOk(index) ? "true" : "false", "counter:", counter.load(), "fid:", fid, "offset:", offset)); + for (auto const i : data) + LOG(LINFO, (i)); + throw; + } +// LOG(LINFO, ("Correct type index:", index, ". header:", header, ". Size of data:", data, +// ". count:", count, "type:", type, "i:", i, +// "Is index ok:", c.IsIndexOk(index) ? "true" : "false")); +} diff --git a/indexer/feature.hpp b/indexer/feature.hpp index bdb7fe62fc8..a5e971326e9 100644 --- a/indexer/feature.hpp +++ b/indexer/feature.hpp @@ -37,6 +37,8 @@ class FeatureType FeatureType(feature::SharedLoadInfo const * loadInfo, std::vector && buffer, feature::MetadataIndex const * metadataIndex); FeatureType(osm::MapObject const & emo); + FeatureType(feature::SharedLoadInfo const * loadInfo, std::vector && buffer, + feature::MetadataIndex const * metadataIndex, uint32_t offset); feature::GeomType GetGeomType() const; FeatureParamsBase & GetParams() { return m_params; } @@ -255,5 +257,10 @@ class FeatureType InnerGeomStat m_innerStats; + uint32_t m_offset = 0; + DISALLOW_COPY_AND_MOVE(FeatureType); }; + +void CheckFeatureTypeData(std::vector const & data, uint64_t offset, uint32_t index, + uint32_t recordSize); diff --git a/indexer/features_offsets_table.cpp b/indexer/features_offsets_table.cpp index b8acf37f81d..2c1f9ce7ff1 100644 --- a/indexer/features_offsets_table.cpp +++ b/indexer/features_offsets_table.cpp @@ -19,6 +19,8 @@ using namespace std; namespace feature { + bool FeaturesOffsetsTable::m_log = false; + void FeaturesOffsetsTable::Builder::PushOffset(uint32_t const offset) { ASSERT(m_offsets.empty() || m_offsets.back() < offset, ()); @@ -28,10 +30,14 @@ namespace feature FeaturesOffsetsTable::FeaturesOffsetsTable(succinct::elias_fano::elias_fano_builder & builder) : m_table(&builder) { + if (m_log) + LOG(LINFO, ("FeaturesOffsetsTable::FeaturesOffsetsTable()")); } FeaturesOffsetsTable::FeaturesOffsetsTable(string const & filePath) { + if (m_log) + LOG(LINFO, ("FeaturesOffsetsTable::FeaturesOffsetsTable() filePath:", filePath)); m_pReader.reset(new MmapReader(filePath)); succinct::mapper::map(m_table, reinterpret_cast(m_pReader->Data())); } @@ -68,6 +74,9 @@ namespace feature // static unique_ptr FeaturesOffsetsTable::Load(FilesContainerR const & cont) { + if (m_log) + LOG(LINFO, ("FeaturesOffsetsTable::Load()")); + unique_ptr table(new FeaturesOffsetsTable()); table->m_file.Open(cont.GetFileName()); @@ -90,6 +99,8 @@ namespace feature void FeaturesOffsetsTable::Save(string const & filePath) { + if (m_log) + LOG(LINFO, ("FeaturesOffsetsTable::Save()")); LOG(LINFO, ("Saving features offsets table to ", filePath)); string const fileNameTmp = filePath + EXTENSION_TMP; succinct::mapper::freeze(m_table, fileNameTmp.c_str()); @@ -98,12 +109,16 @@ namespace feature uint32_t FeaturesOffsetsTable::GetFeatureOffset(size_t index) const { + if (m_log) + LOG(LINFO, (threads::GetCurrentThreadID(), "FeaturesOffsetsTable::GetFeatureOffset()", index)); ASSERT_LESS(index, size(), ("Index out of bounds", index, size())); return static_cast(m_table.select(index)); } size_t FeaturesOffsetsTable::GetFeatureIndexbyOffset(uint32_t offset) const { + if (m_log) + LOG(LINFO, ("FeaturesOffsetsTable::GetFeatureIndexbyOffset()", offset)); ASSERT_GREATER(size(), 0, ("We must not ask empty table")); ASSERT_LESS_OR_EQUAL(offset, m_table.select(size() - 1), ("Offset out of bounds", offset, m_table.select(size() - 1))); diff --git a/indexer/features_offsets_table.hpp b/indexer/features_offsets_table.hpp index 61e437bc264..fd873eae8d3 100644 --- a/indexer/features_offsets_table.hpp +++ b/indexer/features_offsets_table.hpp @@ -93,6 +93,8 @@ namespace feature /// can be used in benchmarks, logging, etc. // size_t byte_size() { return static_cast(succinct::mapper::size_of(m_table)); } + static void SetLog(bool flag) { m_log = flag; } + private: FeaturesOffsetsTable(succinct::elias_fano::elias_fano_builder & builder); FeaturesOffsetsTable(std::string const & filePath); @@ -105,6 +107,7 @@ namespace feature detail::MappedFile m_file; detail::MappedFile::Handle m_handle; + static bool m_log; }; // Builds feature offsets table in an mwm or rebuilds an existing diff --git a/indexer/features_vector.cpp b/indexer/features_vector.cpp index 2ca40eaf959..5af843a2c3f 100644 --- a/indexer/features_vector.cpp +++ b/indexer/features_vector.cpp @@ -1,4 +1,5 @@ #include "features_vector.hpp" +#include "feature.hpp" #include "features_offsets_table.hpp" #include "data_factory.hpp" @@ -7,9 +8,12 @@ std::unique_ptr FeaturesVector::GetByIndex(uint32_t index) const { - auto const ftOffset = m_table ? m_table->GetFeatureOffset(index) : index; - return std::make_unique(&m_loadInfo, m_recordReader->ReadRecord(ftOffset), - m_metaidx.get()); + uint32_t ftOffset = 0; + ftOffset = m_table ? m_table->GetFeatureOffset(index) : index; +// if (index == 333004 || index == 468000 || index == 664105) +// LOG(LCRITICAL, (index, ftOffset)); + return std::make_unique(&m_loadInfo, m_recordReader->ReadRecord(ftOffset, index), + m_metaidx.get(), ftOffset); } size_t FeaturesVector::GetNumFeatures() const diff --git a/indexer/types_mapping.hpp b/indexer/types_mapping.hpp index 71d3dfec5ed..1e32e065d09 100644 --- a/indexer/types_mapping.hpp +++ b/indexer/types_mapping.hpp @@ -17,10 +17,12 @@ class IndexAndTypeMapping // Throws std::out_of_range exception. uint32_t GetType(uint32_t ind) const { - ASSERT_LESS ( ind, m_types.size(), () ); + ASSERT_LESS(ind, m_types.size(), ()); return m_types.at(ind); } + bool IsIndexOk(uint32_t ind) const { return ind < m_types.size(); } + uint32_t GetIndex(uint32_t t) const; /// For Debug purposes only. diff --git a/map/framework.cpp b/map/framework.cpp index 0306749e068..0c81866e137 100644 --- a/map/framework.cpp +++ b/map/framework.cpp @@ -1481,6 +1481,7 @@ void Framework::MemoryWarning() void Framework::EnterBackground() { + LOG(LINFO, ("Framework::EnterBackground()")); m_startBackgroundTime = base::Timer::LocalTime(); settings::Set("LastEnterBackground", m_startBackgroundTime); @@ -1507,6 +1508,7 @@ void Framework::EnterBackground() void Framework::EnterForeground() { + LOG(LINFO, ("Framework::EnterForeground()")); m_startForegroundTime = base::Timer::LocalTime(); if (m_drapeEngine != nullptr && m_startBackgroundTime != 0.0) { diff --git a/routing/base/astar_algorithm.hpp b/routing/base/astar_algorithm.hpp index 1d774693e88..ddd0b297568 100644 --- a/routing/base/astar_algorithm.hpp +++ b/routing/base/astar_algorithm.hpp @@ -5,14 +5,20 @@ #include "routing/base/astar_weight.hpp" #include "routing/base/routing_result.hpp" +#include "indexer/features_offsets_table.hpp" + #include "base/assert.hpp" #include "base/cancellable.hpp" +#include "base/fifo_cache.hpp" #include "base/logging.hpp" #include +#include #include +#include #include #include +#include #include #include #include @@ -76,11 +82,12 @@ class AStarAlgorithm typename LengthChecker = astar::DefaultLengthChecker> struct Params { - Params(Graph & graph, Vertex const & startVertex, Vertex const & finalVertex, + Params(Graph & graph, Graph & graphBwd, Vertex const & startVertex, Vertex const & finalVertex, std::vector const * prevRoute, base::Cancellable const & cancellable, Visitor && onVisitedVertexCallback = astar::DefaultVisitor(), LengthChecker && checkLengthCallback = astar::DefaultLengthChecker()) : m_graph(graph) + , m_graphBwd(graphBwd) , m_startVertex(startVertex) , m_finalVertex(finalVertex) , m_prevRoute(prevRoute) @@ -91,6 +98,7 @@ class AStarAlgorithm } Graph & m_graph; + Graph & m_graphBwd; Weight const m_weightEpsilon = m_graph.GetAStarWeightEpsilon(); Vertex const m_startVertex; // Used for FindPath, FindPathBidirectional. @@ -110,6 +118,7 @@ class AStarAlgorithm std::vector const * prevRoute, LengthChecker && checkLengthCallback = astar::DefaultLengthChecker()) : m_graph(graph) + , m_graphBwd(graph) , m_startVertex(startVertex) , m_finalVertex(finalVertex) , m_prevRoute(prevRoute) @@ -118,6 +127,7 @@ class AStarAlgorithm } Graph & m_graph; + Graph & m_graphBwd; Weight const m_weightEpsilon = m_graph.GetAStarWeightEpsilon(); Vertex const m_startVertex; // Used for FindPath, FindPathBidirectional. @@ -211,6 +221,8 @@ class AStarAlgorithm template Result FindPathBidirectional(P & params, RoutingResult & result) const; + template + Result FindPathBidirectionalOneThread(P & params, RoutingResult & result) const; // Adjust route to the previous one. // Expects |params.m_checkLengthCallback| to check wave propagation limit. @@ -267,12 +279,14 @@ class AStarAlgorithm { using Parents = typename Graph::Parents; - BidirectionalStepContext(bool forward, Vertex const & startVertex, Vertex const & finalVertex, - Graph & graph) - : forward(forward) - , startVertex(startVertex) - , finalVertex(finalVertex) - , graph(graph) + BidirectionalStepContext(std::mutex & mtx, std::mutex & mtxGr, bool forward, Vertex const & startVertex, + Vertex const & finalVertex, Graph & graph) + : mtx(mtx) + , mtxGr(mtxGr) + , forward(forward) + , startVertex(startVertex) + , finalVertex(finalVertex) + , graph(graph) { bestVertex = forward ? startVertex : finalVertex; pS = ConsistentHeuristic(bestVertex); @@ -303,8 +317,9 @@ class AStarAlgorithm // particular routes when debugging turned out to be easier. Weight ConsistentHeuristic(Vertex const & v) const { - auto const piF = graph.HeuristicCostEstimate(v, finalVertex); - auto const piR = graph.HeuristicCostEstimate(v, startVertex); + Weight piF = graph.HeuristicCostEstimate(v, finalVertex, forward); + Weight piR = graph.HeuristicCostEstimate(v, startVertex, forward); + if (forward) { /// @todo careful: with this "return" here and below in the Backward case @@ -330,7 +345,7 @@ class AStarAlgorithm bestDistance.insert_or_assign(state.vertex, state.distance); } - std::optional GetDistance(Vertex const & vertex) + std::optional GetDistance(Vertex const & vertex) const { auto const it = bestDistance.find(vertex); return it != bestDistance.cend() ? std::optional(it->second) : std::nullopt; @@ -345,6 +360,8 @@ class AStarAlgorithm { auto const realDistance = state.distance + pS - state.heuristic; astar::VertexData const data(state.vertex, realDistance); + +// std::lock_guard lock(mtxGr); if (forward) graph.GetOutgoingEdgesList(data, adj); else @@ -353,6 +370,26 @@ class AStarAlgorithm Parents & GetParents() { return parent; } + bool ExistsStateWithBetterDistanceLock(State const & state, Weight const & eps = Weight(0.0)) + { + std::lock_guard lock(mtx); + return ExistsStateWithBetterDistance(state, eps); + } + + void UpdateDistanceLock(State const & state) + { + std::lock_guard lock(mtx); + UpdateDistance(state); + } + + std::optional GetDistanceLock(Vertex const & vertex) + { + std::lock_guard lock(mtx); + return GetDistance(vertex); + } + + std::mutex & mtx; + std::mutex & mtxGr; bool const forward; Vertex const & startVertex; Vertex const & finalVertex; @@ -482,8 +519,8 @@ AStarAlgorithm::FindPath(P & params, RoutingResult typename AStarAlgorithm::Result AStarAlgorithm::FindPathBidirectional(P & params, RoutingResult & result) const +{ + auto const epsilon = params.m_weightEpsilon; + auto & graph = params.m_graph; + auto & graphBwd = params.m_graph; // params.m_graphBwd; + auto const & finalVertex = params.m_finalVertex; + auto const & startVertex = params.m_startVertex; + + std::mutex mtx; + std::mutex mtxGr; + BidirectionalStepContext forward(mtx, mtxGr, true /* forward */, startVertex, finalVertex, graph); + BidirectionalStepContext backward(mtx, mtxGr, false /* forward */, startVertex, finalVertex, graphBwd); + + auto & forwardParents = forward.GetParents(); + auto & backwardParents = backward.GetParents(); + + bool foundAnyPath = false; + auto bestPathReducedLength = kZeroDistance; + auto bestPathRealLength = kZeroDistance; + + forward.UpdateDistance(State(startVertex, kZeroDistance)); + forward.queue.push(State(startVertex, kZeroDistance, forward.ConsistentHeuristic(startVertex))); + + backward.UpdateDistance(State(finalVertex, kZeroDistance)); + backward.queue.push(State(finalVertex, kZeroDistance, backward.ConsistentHeuristic(finalVertex))); + + auto wave = [&epsilon](BidirectionalStepContext & context, std::atomic & queueIsEmpty, + BidirectionalStepContext & oppositeContext, std::atomic & oppositeQueueIsEmpty) + { + LOG(LINFO, ("---FindPath-------wave---------------------------", context.forward ? "forward" : "backward")); + size_t i = 0; + std::vector adj; + while (!context.queue.empty() /* && !oppositeQueueIsEmpty.load() */) + { + // TODO Take care exception top/pop problem. + State const stateV = context.queue.top(); + context.queue.pop(); + + if (context.ExistsStateWithBetterDistanceLock(stateV)) + continue; + +// params.m_onVisitedVertexCallback(stateV.vertex, context.forward ? context.finalVertex : context.startVertex); + // @TODO Think about concurrent access to graph. + context.GetAdjacencyList(stateV, adj); + auto const & pV = stateV.heuristic; + for (auto const & edge : adj) + { + State stateW(edge.GetTarget(), kZeroDistance); + + if (stateV.vertex == stateW.vertex) + continue; + + auto const weight = edge.GetWeight(); + auto const pW = context.ConsistentHeuristic(stateW.vertex); + auto const reducedWeight = weight + pW - pV; + + CHECK_GREATER_OR_EQUAL( + reducedWeight, -epsilon, + ("Invariant violated for:", "v =", stateV.vertex, "w =", stateW.vertex)); + + stateW.distance = stateV.distance + std::max(reducedWeight, kZeroDistance); + +// auto const fullLength = weight + stateV.distance + context.pS - pV; + +// if (!params.m_checkLengthCallback(fullLength)) +// continue; + + if (context.ExistsStateWithBetterDistanceLock(stateW, epsilon)) + continue; + + stateW.heuristic = pW; + context.UpdateDistanceLock(stateW); + context.UpdateParent(stateW.vertex, stateV.vertex); + ++i; + if (oppositeContext.GetDistanceLock(stateW.vertex)) // i == 896199 + { + LOG(LINFO, ("---FindPath-------wave end---------------------------", context.forward ? "forward" : "backward", stateW.vertex, i)); + return; // The waves are intersected. + } + + if (stateW.vertex != (context.forward ? context.finalVertex : context.startVertex)) + context.queue.push(stateW); + } + } + + if (context.queue.empty()) + queueIsEmpty.store(true); + LOG(LINFO, ("----FindPath------wave end (empty)---------------------------", context.forward ? "forward" : "backward")); + }; + +// std::atomic foundAnyPathF; + std::atomic fwdIsEmpty; + std::atomic bwdIsEmpty; + + PeriodicPollCancellable periodicCancellable(params.m_cancellable); + + // Starting a thread. + { +// feature::FeaturesOffsetsTable::SetLog(true); + base::ScopedTimerWithLog timer("Wave"); + auto backwardWave = std::async(std::launch::async, wave, std::ref(backward), + std::ref(bwdIsEmpty), std::ref(forward), std::ref(fwdIsEmpty)); + wave(forward, fwdIsEmpty, backward, bwdIsEmpty); + backwardWave.get(); + } + LOG(LINFO, ("-------FindPath-------Finished-----------------")); + + // To use the search code both for backward and forward directions + // we keep the pointers to everything related to the search in the + // 'current' and 'next' directions. Swapping these pointers indicates + // changing the end we are searching from. + BidirectionalStepContext * cur = &forward; + BidirectionalStepContext * nxt = &backward; + + auto const getResult = [&]() { + if (!params.m_checkLengthCallback(bestPathRealLength)) + return Result::NoPath; + + ReconstructPathBidirectional(cur->bestVertex, nxt->bestVertex, cur->parent, nxt->parent, + result.m_path); + result.m_distance = bestPathRealLength; + CHECK(!result.m_path.empty(), ()); + if (!cur->forward) + reverse(result.m_path.begin(), result.m_path.end()); + + return Result::OK; + }; + + std::vector adj; + uint32_t steps = 0; + + // Waves have been intersected. The routing is finished in one thread. + while (!cur->queue.empty() && !nxt->queue.empty()) + { + ++steps; + + if (periodicCancellable.IsCancelled()) + return Result::Cancelled; + + if (steps % kQueueSwitchPeriod == 0) + std::swap(cur, nxt); + + if (foundAnyPath) + { + auto const curTop = cur->TopDistance(); + auto const nxtTop = nxt->TopDistance(); + + // The intuition behind this is that we cannot obtain a path shorter + // than the left side of the inequality because that is how any path we find + // will look like (see comment for curPathReducedLength below). + // We do not yet have the proof that we will not miss a good path by doing so. + + // The shortest reduced path corresponds to the shortest real path + // because the heuristic we use are consistent. + // It would be a mistake to make a decision based on real path lengths because + // several top states in a priority queue may have equal reduced path lengths and + // different real path lengths. + + if (curTop + nxtTop >= bestPathReducedLength - epsilon) + return getResult(); + } + + State const stateV = cur->queue.top(); + cur->queue.pop(); + + if (cur->ExistsStateWithBetterDistance(stateV)) + continue; + + params.m_onVisitedVertexCallback(stateV.vertex, + cur->forward ? cur->finalVertex : cur->startVertex); + + cur->GetAdjacencyList(stateV, adj); + auto const & pV = stateV.heuristic; + for (auto const & edge : adj) + { + State stateW(edge.GetTarget(), kZeroDistance); + + if (stateV.vertex == stateW.vertex) + continue; + + auto const weight = edge.GetWeight(); + auto const pW = cur->ConsistentHeuristic(stateW.vertex); + auto const reducedWeight = weight + pW - pV; + + CHECK_GREATER_OR_EQUAL(reducedWeight, -epsilon, + ("Invariant violated for:", "v =", stateV.vertex, "w =", stateW.vertex)); + + stateW.distance = stateV.distance + std::max(reducedWeight, kZeroDistance); + + auto const fullLength = weight + stateV.distance + cur->pS - pV; + if (!params.m_checkLengthCallback(fullLength)) + continue; + + if (cur->ExistsStateWithBetterDistance(stateW, epsilon)) + continue; + + stateW.heuristic = pW; + cur->UpdateDistance(stateW); + cur->UpdateParent(stateW.vertex, stateV.vertex); + + if (auto op = nxt->GetDistance(stateW.vertex); op) + { + auto const & distW = *op; + // Reduced length that the path we've just found has in the original graph: + // find the reduced length of the path's parts in the reduced forward and backward graphs. + auto const curPathReducedLength = stateW.distance + distW; + // No epsilon here: it is ok to overshoot slightly. + if ((!foundAnyPath || bestPathReducedLength > curPathReducedLength) && + graph.AreWavesConnectible(forwardParents, stateW.vertex, backwardParents)) + { + bestPathReducedLength = curPathReducedLength; + + bestPathRealLength = stateV.distance + weight + distW; + bestPathRealLength += cur->pS - pV; + bestPathRealLength += nxt->pS - nxt->ConsistentHeuristic(stateW.vertex); + + foundAnyPath = true; + cur->bestVertex = stateV.vertex; + nxt->bestVertex = stateW.vertex; + } + } + + if (stateW.vertex != (cur->forward ? cur->finalVertex : cur->startVertex)) + cur->queue.push(stateW); + } + } + + if (foundAnyPath) + return getResult(); + + return Result::NoPath; +} + +template +template +typename AStarAlgorithm::Result +AStarAlgorithm::FindPathBidirectionalOneThread(P & params, + RoutingResult & result) const { auto const epsilon = params.m_weightEpsilon; auto & graph = params.m_graph; auto const & finalVertex = params.m_finalVertex; auto const & startVertex = params.m_startVertex; - BidirectionalStepContext forward(true /* forward */, startVertex, finalVertex, graph); - BidirectionalStepContext backward(false /* forward */, startVertex, finalVertex, graph); + std::mutex mtx; + BidirectionalStepContext forward(mtx, true /* forward */, startVertex, finalVertex, graph); + BidirectionalStepContext backward(mtx, false /* forward */, startVertex, finalVertex, graph); auto & forwardParents = forward.GetParents(); auto & backwardParents = backward.GetParents(); diff --git a/routing/base/astar_graph.hpp b/routing/base/astar_graph.hpp index 37e95e34665..0e5f815b61d 100644 --- a/routing/base/astar_graph.hpp +++ b/routing/base/astar_graph.hpp @@ -20,7 +20,7 @@ class AStarGraph using Parents = ska::bytell_hash_map; - virtual Weight HeuristicCostEstimate(Vertex const & from, Vertex const & to) = 0; + virtual Weight HeuristicCostEstimate(Vertex const & from, Vertex const & to, bool isOutgoing) = 0; virtual void GetOutgoingEdgesList(astar::VertexData const & vertexData, std::vector & edges) = 0; diff --git a/routing/cross_mwm_index_graph.hpp b/routing/cross_mwm_index_graph.hpp index f4a5a12ae77..b1528a90bf3 100644 --- a/routing/cross_mwm_index_graph.hpp +++ b/routing/cross_mwm_index_graph.hpp @@ -139,10 +139,10 @@ class CrossMwmIndexGraph final // There are same in common, but in case of different version of mwms // their's geometry can differ from each other. Because of this we can not // build the route, because we fail in astar_algorithm.hpp CHECK(invariant) sometimes. - if (SegmentsAreEqualByGeometry(s, *twinSeg)) +// if (SegmentsAreEqualByGeometry(s, *twinSeg)) twins.push_back(*twinSeg); - else - LOG(LINFO, ("Bad cross mwm feature, differ in geometry. Current:", s, ", twin:", *twinSeg)); +// else +// LOG(LINFO, ("Bad cross mwm feature, differ in geometry. Current:", s, ", twin:", *twinSeg)); } } @@ -164,6 +164,7 @@ class CrossMwmIndexGraph final CrossMwmConnector const & GetCrossMwmConnectorWithTransitions(NumMwmId numMwmId) { + // @TODO |m_connectors| should be protected. auto const it = m_connectors.find(numMwmId); if (it != m_connectors.cend()) return it->second; diff --git a/routing/edge_estimator.cpp b/routing/edge_estimator.cpp index ca01b1be80d..e4f0cad3a0b 100644 --- a/routing/edge_estimator.cpp +++ b/routing/edge_estimator.cpp @@ -177,7 +177,7 @@ class PedestrianEstimator final : public EdgeEstimator } double CalcSegmentWeight(Segment const & segment, RoadGeometry const & road, - Purpose purpose) const override + Purpose purpose, bool isOutgoing) const override { return CalcClimbSegment(purpose, segment, road, GetPedestrianClimbPenalty); } @@ -206,7 +206,7 @@ class BicycleEstimator final : public EdgeEstimator } double CalcSegmentWeight(Segment const & segment, RoadGeometry const & road, - Purpose purpose) const override + Purpose purpose, bool isOutgoing) const override { return CalcClimbSegment(purpose, segment, road, GetBicycleClimbPenalty); } @@ -221,7 +221,7 @@ class CarEstimator final : public EdgeEstimator // EdgeEstimator overrides: double CalcSegmentWeight(Segment const & segment, RoadGeometry const & road, - Purpose purpose) const override; + Purpose purpose, bool isOutgoing) const override; double GetUTurnPenalty(Purpose /* purpose */) const override; double GetFerryLandingPenalty(Purpose purpose) const override; @@ -237,7 +237,7 @@ CarEstimator::CarEstimator(shared_ptr trafficStash, double maxWeig } double CarEstimator::CalcSegmentWeight(Segment const & segment, RoadGeometry const & road, - Purpose purpose) const + Purpose purpose, bool isOutgoing) const { return CalcSegment(purpose, segment, road); } diff --git a/routing/edge_estimator.hpp b/routing/edge_estimator.hpp index 362a91ebe6e..7fe43bbe8ab 100644 --- a/routing/edge_estimator.hpp +++ b/routing/edge_estimator.hpp @@ -45,7 +45,7 @@ class EdgeEstimator double CalcOffroad(ms::LatLon const & from, ms::LatLon const & to, Purpose purpose) const; virtual double CalcSegmentWeight(Segment const & segment, RoadGeometry const & road, - Purpose purpose) const = 0; + Purpose purpose, bool isOutgoing) const = 0; virtual double GetUTurnPenalty(Purpose purpose) const = 0; virtual double GetFerryLandingPenalty(Purpose purpose) const = 0; diff --git a/routing/fake_ending.cpp b/routing/fake_ending.cpp index de96339a702..0559143f24b 100644 --- a/routing/fake_ending.cpp +++ b/routing/fake_ending.cpp @@ -61,9 +61,9 @@ FakeEnding MakeFakeEnding(vector const & segments, m2::PointD const & p { auto const & segment = segments[i]; - bool const oneWay = graph.IsOneWay(segment.GetMwmId(), segment.GetFeatureId()); - auto const & frontJunction = graph.GetJunction(segment, true /* front */); - auto const & backJunction = graph.GetJunction(segment, false /* front */); + bool const oneWay = graph.IsOneWay(segment.GetMwmId(), segment.GetFeatureId(), true); + auto const & frontJunction = graph.GetJunction(segment, true /* front */, true); + auto const & backJunction = graph.GetJunction(segment, false /* front */, true); auto const & projectedJunction = CalcProjectionToSegment(backJunction, frontJunction, point); ending.m_projections.emplace_back(segment, oneWay, frontJunction, backJunction, @@ -79,7 +79,7 @@ FakeEnding MakeFakeEnding(vector const & segments, m2::PointD const & p FakeEnding MakeFakeEnding(Segment const & segment, m2::PointD const & point, IndexGraph & graph) { - auto const & road = graph.GetGeometry().GetRoad(segment.GetFeatureId()); + auto const & road = graph.GetGeometry().GetRoad(segment.GetFeatureId(), true /* isOutgoing */); bool const oneWay = road.IsOneWay(); auto const & frontJunction = road.GetJunction(segment.GetPointId(true /* front */)); auto const & backJunction = road.GetJunction(segment.GetPointId(false /* front */)); diff --git a/routing/geometry.cpp b/routing/geometry.cpp index 0d7833c8a3e..3f71db74045 100644 --- a/routing/geometry.cpp +++ b/routing/geometry.cpp @@ -16,6 +16,7 @@ #include "base/string_utils.hpp" #include +#include #include using namespace routing; @@ -25,7 +26,7 @@ namespace { // @TODO(bykoianko) Consider setting cache size based on available memory. // Maximum road geometry cache size in items. -size_t constexpr kRoadsCacheSize = 5000; +size_t constexpr kRoadsCacheSize = 3500; double CalcFerryDurationHours(string const & durationHours, double roadLenKm) { @@ -64,12 +65,13 @@ class GeometryLoaderImpl final : public GeometryLoader AttrLoader attrLoader, bool loadAltitudes); // GeometryLoader overrides: - void Load(uint32_t featureId, RoadGeometry & road) override; + void Load(uint32_t featureId, bool isOutgoing, RoadGeometry & road) override; private: shared_ptr m_vehicleModel; AttrLoader m_attrLoader; FeaturesLoaderGuard m_guard; + FeaturesLoaderGuard m_guardBwd; string const m_country; feature::AltitudeLoader m_altitudeLoader; bool const m_loadAltitudes; @@ -82,6 +84,7 @@ GeometryLoaderImpl::GeometryLoaderImpl(DataSource const & dataSource, : m_vehicleModel(move(vehicleModel)) , m_attrLoader(move(attrLoader)) , m_guard(dataSource, handle.GetId()) + , m_guardBwd(dataSource, handle.GetId()) , m_country(handle.GetInfo()->GetCountryName()) , m_altitudeLoader(dataSource, handle.GetId()) , m_loadAltitudes(loadAltitudes) @@ -92,21 +95,26 @@ GeometryLoaderImpl::GeometryLoaderImpl(DataSource const & dataSource, CHECK(m_attrLoader.m_maxspeeds, ()); } -void GeometryLoaderImpl::Load(uint32_t featureId, RoadGeometry & road) +//std::mutex mtx; + +void GeometryLoaderImpl::Load(uint32_t featureId, bool isOutgoing, RoadGeometry & road) { - auto feature = m_guard.GetFeatureByIndex(featureId); - if (!feature) - MYTHROW(RoutingException, ("Feature", featureId, "not found in ", m_country)); +// std::unique_lock guard(mtx); +auto feature = + isOutgoing ? m_guard.GetFeatureByIndex(featureId) : m_guardBwd.GetFeatureByIndex(featureId); +if (!feature) + MYTHROW(RoutingException, ("Feature", featureId, "not found in ", m_country)); - feature->ParseGeometry(FeatureType::BEST_GEOMETRY); +feature->ParseGeometry(FeatureType::BEST_GEOMETRY); +// guard.unlock(); geometry::Altitudes const * altitudes = nullptr; - if (m_loadAltitudes) - altitudes = &(m_altitudeLoader.GetAltitudes(featureId, feature->GetPointsCount())); +// if (m_loadAltitudes) +// altitudes = &(m_altitudeLoader.GetAltitudes(featureId, feature->GetPointsCount())); road.Load(*m_vehicleModel, *feature, altitudes, m_attrLoader.m_cityRoads->IsCityRoad(featureId), m_attrLoader.m_maxspeeds->GetMaxspeed(featureId)); - m_altitudeLoader.ClearCache(); +// m_altitudeLoader.ClearCache(); } // FileGeometryLoader ------------------------------------------------------------------------------ @@ -116,7 +124,7 @@ class FileGeometryLoader final : public GeometryLoader FileGeometryLoader(string const & fileName, shared_ptr vehicleModel); // GeometryLoader overrides: - void Load(uint32_t featureId, RoadGeometry & road) override; + void Load(uint32_t featureId, bool isOutgoing, RoadGeometry & road) override; private: FeaturesVectorTest m_featuresVector; @@ -149,8 +157,9 @@ FileGeometryLoader::FileGeometryLoader(string const & fileName, CHECK(m_vehicleModel, ()); } -void FileGeometryLoader::Load(uint32_t featureId, RoadGeometry & road) +void FileGeometryLoader::Load(uint32_t featureId, bool isOutgoing, RoadGeometry & road) { + CHECK(false, ("FileGeometryLoader() is not ready for multithreading.")); auto feature = m_featuresVector.GetVector().GetByIndex(featureId); CHECK(feature, ()); feature->ParseGeometry(FeatureType::BEST_GEOMETRY); @@ -186,7 +195,6 @@ void RoadGeometry::Load(VehicleModelInterface const & vehicleModel, FeatureType CHECK(altitudes == nullptr || altitudes->size() == feature.GetPointsCount(), ()); m_valid = vehicleModel.IsRoad(feature); - m_isOneWay = vehicleModel.IsOneWay(feature); m_forwardSpeed = vehicleModel.GetSpeed(feature, {true /* forward */, inCity, maxspeed}); m_backwardSpeed = vehicleModel.GetSpeed(feature, {false /* forward */, inCity, maxspeed}); m_highwayType = vehicleModel.GetHighwayType(feature); @@ -257,17 +265,24 @@ Geometry::Geometry(unique_ptr loader) : m_loader(move(loader)) , m_featureIdToRoad(make_unique( kRoadsCacheSize, - [this](uint32_t featureId, RoadGeometry & road) { m_loader->Load(featureId, road); })) + [this](uint32_t featureId, RoadGeometry & road) { LoadGeomLock(featureId, true /* isOutgoing */, road); })) + , m_featureIdToRoadBwd(make_unique( + kRoadsCacheSize, + [this](uint32_t featureId, RoadGeometry & road) { LoadGeomLock(featureId, false /* isOutgoing */, road); })) { CHECK(m_loader, ()); } -RoadGeometry const & Geometry::GetRoad(uint32_t featureId) +RoadGeometry const & Geometry::GetRoad(uint32_t featureId, bool isOutgoing) { ASSERT(m_featureIdToRoad, ()); ASSERT(m_loader, ()); - return m_featureIdToRoad->GetValue(featureId); +// std::lock_guard lock(m_loaderMtx); + if (isOutgoing) + return m_featureIdToRoad->GetValue(featureId); + + return m_featureIdToRoadBwd->GetValue(featureId); } // static diff --git a/routing/geometry.hpp b/routing/geometry.hpp index 1d60cc4f3c4..975641a382b 100644 --- a/routing/geometry.hpp +++ b/routing/geometry.hpp @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -108,7 +109,7 @@ class GeometryLoader public: virtual ~GeometryLoader() = default; - virtual void Load(uint32_t featureId, RoadGeometry & road) = 0; + virtual void Load(uint32_t featureId, bool isOutgoing, RoadGeometry & road) = 0; // handle should be alive: it is caller responsibility to check it. static std::unique_ptr Create(DataSource const & dataSource, @@ -139,20 +140,29 @@ class Geometry final /// \note The reference returned by the method is valid until the next call of GetRoad() /// of GetPoint() methods. - RoadGeometry const & GetRoad(uint32_t featureId); + RoadGeometry const & GetRoad(uint32_t featureId, bool isOutgoing); /// \note The reference returned by the method is valid until the next call of GetRoad() /// of GetPoint() methods. - ms::LatLon const & GetPoint(RoadPoint const & rp) + ms::LatLon const & GetPoint(RoadPoint const & rp, bool isOutgoing) { - return GetRoad(rp.GetFeatureId()).GetPoint(rp.GetPointId()); + return GetRoad(rp.GetFeatureId(), isOutgoing).GetPoint(rp.GetPointId()); + } + + void LoadGeomLock(uint32_t featureId, bool isOutgoing, RoadGeometry & road) + { +// std::lock_guard lock(m_loaderMtx); + m_loader->Load(featureId, isOutgoing, road); } private: using RoutingFifoCache = FifoCache>; +// std::mutex m_loaderMtx; std::unique_ptr m_loader; +// std::unique_ptr m_loaderBwd; std::unique_ptr m_featureIdToRoad; + std::unique_ptr m_featureIdToRoadBwd; }; } // namespace routing diff --git a/routing/index_graph.cpp b/routing/index_graph.cpp index d168dbda3a8..07a78be8e08 100644 --- a/routing/index_graph.cpp +++ b/routing/index_graph.cpp @@ -59,7 +59,7 @@ bool IndexGraph::IsJointOrEnd(Segment const & segment, bool fromStart) if (pointId == 0) return true; - uint32_t const pointsNumber = GetGeometry().GetRoad(segment.GetFeatureId()).GetPointsCount(); + uint32_t const pointsNumber = GetGeometry().GetRoad(segment.GetFeatureId(), true /* isOutgoing */).GetPointsCount(); return pointId + 1 == pointsNumber; } @@ -112,7 +112,7 @@ void IndexGraph::GetLastPointsForJoint(vector const & children, for (auto const & child : children) { uint32_t const startPointId = child.GetPointId(!isOutgoing /* front */); - uint32_t const pointsNumber = m_geometry->GetRoad(child.GetFeatureId()).GetPointsCount(); + uint32_t const pointsNumber = m_geometry->GetRoad(child.GetFeatureId(), isOutgoing).GetPointsCount(); CHECK_LESS(startPointId, pointsNumber, ()); uint32_t endPointId; @@ -251,7 +251,7 @@ void IndexGraph::GetNeighboringEdges(astar::VertexData con vector & edges, Parents const & parents, bool useAccessConditional) { - RoadGeometry const & road = m_geometry->GetRoad(rp.GetFeatureId()); + RoadGeometry const & road = m_geometry->GetRoad(rp.GetFeatureId(), isOutgoing); if (!road.IsValid()) return; @@ -280,7 +280,7 @@ void IndexGraph::GetNeighboringEdges(astar::VertexData con void IndexGraph::GetSegmentCandidateForRoadPoint(RoadPoint const & rp, NumMwmId numMwmId, bool isOutgoing, std::vector & children) { - RoadGeometry const & road = m_geometry->GetRoad(rp.GetFeatureId()); + RoadGeometry const & road = m_geometry->GetRoad(rp.GetFeatureId(), isOutgoing); if (!road.IsValid()) return; @@ -446,9 +446,9 @@ void IndexGraph::GetNeighboringEdge(astar::VertexData cons edges.emplace_back(to, weight); } -IndexGraph::PenaltyData IndexGraph::GetRoadPenaltyData(Segment const & segment) +IndexGraph::PenaltyData IndexGraph::GetRoadPenaltyData(Segment const & segment, bool isOutgoing) { - auto const & road = m_geometry->GetRoad(segment.GetFeatureId()); + auto const & road = m_geometry->GetRoad(segment.GetFeatureId(), isOutgoing); PenaltyData result(road.IsPassThroughAllowed(), road.GetRoutingOptions().Has(RoutingOptions::Road::Ferry)); @@ -457,10 +457,11 @@ IndexGraph::PenaltyData IndexGraph::GetRoadPenaltyData(Segment const & segment) } RouteWeight IndexGraph::GetPenalties(EdgeEstimator::Purpose purpose, Segment const & u, - Segment const & v, optional const & prevWeight) + Segment const & v, optional const & prevWeight, + bool isOutgoing) { - auto const & fromPenaltyData = GetRoadPenaltyData(u); - auto const & toPenaltyData = GetRoadPenaltyData(v); + auto const & fromPenaltyData = GetRoadPenaltyData(u, isOutgoing); + auto const & toPenaltyData = GetRoadPenaltyData(v, isOutgoing); // Route crosses border of pass-through/non-pass-through area if |u| and |v| have different // pass through restrictions. int8_t const passThroughPenalty = @@ -536,7 +537,7 @@ bool IndexGraph::IsUTurnAndRestricted(Segment const & parent, Segment const & ch uint32_t const featureId = parent.GetFeatureId(); uint32_t const turnPoint = parent.GetPointId(isOutgoing); - auto const & roadGeometry = m_geometry->GetRoad(featureId); + auto const & roadGeometry = m_geometry->GetRoad(featureId, isOutgoing); RoadPoint const rp = parent.GetRoadPoint(isOutgoing); if (m_roadIndex.GetJointId(rp) == Joint::kInvalidId && !roadGeometry.IsEndPointId(turnPoint)) @@ -560,11 +561,11 @@ RouteWeight IndexGraph::CalculateEdgeWeight(EdgeEstimator::Purpose purpose, bool std::optional const & prevWeight) { auto const & segment = isOutgoing ? to : from; - auto const & road = m_geometry->GetRoad(segment.GetFeatureId()); + auto const & road = m_geometry->GetRoad(segment.GetFeatureId(), isOutgoing); - auto const weight = RouteWeight(m_estimator->CalcSegmentWeight(segment, road, purpose)); + auto const weight = RouteWeight(m_estimator->CalcSegmentWeight(segment, road, purpose, isOutgoing)); auto const & penalties = - GetPenalties(purpose, isOutgoing ? from : to, isOutgoing ? to : from, prevWeight); + GetPenalties(purpose, isOutgoing ? from : to, isOutgoing ? to : from, prevWeight, isOutgoing); return weight + penalties; } diff --git a/routing/index_graph.hpp b/routing/index_graph.hpp index 9c45e69cde5..6c66c74e057 100644 --- a/routing/index_graph.hpp +++ b/routing/index_graph.hpp @@ -113,9 +113,9 @@ class IndexGraph final std::vector & lastPoints); WorldGraphMode GetMode() const; - ms::LatLon const & GetPoint(Segment const & segment, bool front) + ms::LatLon const & GetPoint(Segment const & segment, bool front, bool isOutgoing) { - return GetGeometry().GetRoad(segment.GetFeatureId()).GetPoint(segment.GetPointId(front)); + return GetGeometry().GetRoad(segment.GetFeatureId(), isOutgoing).GetPoint(segment.GetPointId(front)); } /// \brief Check, that we can go to |currentFeatureId|. @@ -164,14 +164,14 @@ class IndexGraph final bool m_isFerry; }; - PenaltyData GetRoadPenaltyData(Segment const & segment); + PenaltyData GetRoadPenaltyData(Segment const & segment, bool isOutgoing); /// \brief Calculates penalties for moving from |u| to |v|. /// \param |prevWeight| uses for fetching access:conditional. In fact it is time when user /// will be at |u|. This time is based on start time of route building and weight of calculated /// path until |u|. RouteWeight GetPenalties(EdgeEstimator::Purpose purpose, Segment const & u, Segment const & v, - std::optional const & prevWeight); + std::optional const & prevWeight, bool isOutgoing); void GetSegmentCandidateForRoadPoint(RoadPoint const & rp, NumMwmId numMwmId, bool isOutgoing, std::vector & children); diff --git a/routing/index_graph_loader.cpp b/routing/index_graph_loader.cpp index 95adc4d4d6a..e5264fa40fb 100644 --- a/routing/index_graph_loader.cpp +++ b/routing/index_graph_loader.cpp @@ -20,6 +20,7 @@ #include #include +#include #include #include @@ -54,11 +55,13 @@ class IndexGraphLoaderImpl final : public IndexGraphLoader VehicleType m_vehicleType; bool m_loadAltitudes; +// std::mutex m_dataSourceMtx; DataSource & m_dataSource; shared_ptr m_numMwmIds; shared_ptr m_vehicleModelFactory; shared_ptr m_estimator; + std::mutex m_graphsMtx; unordered_map m_graphs; unordered_map>> m_cachedCameras; @@ -90,20 +93,26 @@ IndexGraphLoaderImpl::IndexGraphLoaderImpl( Geometry & IndexGraphLoaderImpl::GetGeometry(NumMwmId numMwmId) { - auto it = m_graphs.find(numMwmId); - if (it != m_graphs.end()) - return *it->second.m_geometry; + { + std::lock_guard guard(m_graphsMtx); + auto it = m_graphs.find(numMwmId); + if (it != m_graphs.end()) + return *it->second.m_geometry; + } return *CreateGeometry(numMwmId).m_geometry; } IndexGraph & IndexGraphLoaderImpl::GetIndexGraph(NumMwmId numMwmId) { - auto it = m_graphs.find(numMwmId); - if (it != m_graphs.end()) { - return it->second.m_indexGraph ? *it->second.m_indexGraph - : *CreateIndexGraph(numMwmId, it->second).m_indexGraph; + std::lock_guard guard(m_graphsMtx); + auto it = m_graphs.find(numMwmId); + if (it != m_graphs.end()) + { + return it->second.m_indexGraph ? *it->second.m_indexGraph + : *CreateIndexGraph(numMwmId, it->second).m_indexGraph; + } } return *CreateIndexGraph(numMwmId, CreateGeometry(numMwmId)).m_indexGraph; @@ -187,16 +196,21 @@ vector IndexGraphLoaderImpl::GetSpeedCameraInfo(Segme IndexGraphLoaderImpl::GraphAttrs & IndexGraphLoaderImpl::CreateGeometry(NumMwmId numMwmId) { platform::CountryFile const & file = m_numMwmIds->GetFile(numMwmId); + // @TODO No protection!!!!! MwmSet::MwmHandle handle = m_dataSource.GetMwmHandleByCountryFile(file); if (!handle.IsAlive()) MYTHROW(RoutingException, ("Can't get mwm handle for", file)); + // @TODO No protection!!!!! shared_ptr vehicleModel = m_vehicleModelFactory->GetVehicleModelForCountry(file.GetName()); - auto & graph = m_graphs[numMwmId]; - graph.m_geometry = make_shared(GeometryLoader::Create( + auto geom = make_shared(GeometryLoader::Create( m_dataSource, handle, vehicleModel, AttrLoader(m_dataSource, handle), m_loadAltitudes)); + + std::lock_guard guard(m_graphsMtx); + auto & graph = m_graphs[numMwmId]; + graph.m_geometry = std::move(geom); return graph; } @@ -219,7 +233,11 @@ IndexGraphLoaderImpl::GraphAttrs & IndexGraphLoaderImpl::CreateIndexGraph( return graph; } -void IndexGraphLoaderImpl::Clear() { m_graphs.clear(); } +void IndexGraphLoaderImpl::Clear() +{ + std::lock_guard guard(m_graphsMtx); + m_graphs.clear(); +} bool ReadRoadAccessFromMwm(MwmValue const & mwmValue, VehicleType vehicleType, RoadAccess & roadAccess) diff --git a/routing/index_graph_starter.cpp b/routing/index_graph_starter.cpp index 4a9e07ae1ac..63ac498ce72 100644 --- a/routing/index_graph_starter.cpp +++ b/routing/index_graph_starter.cpp @@ -76,8 +76,8 @@ IndexGraphStarter::IndexGraphStarter(FakeEnding const & startEnding, m_otherEndings.push_back(startEnding); m_otherEndings.push_back(finishEnding); - auto const startPoint = GetPoint(GetStartSegment(), false /* front */); - auto const finishPoint = GetPoint(GetFinishSegment(), true /* front */); + auto const startPoint = GetPoint(GetStartSegment(), false /* front */, true /* isOutgoing */); + auto const finishPoint = GetPoint(GetFinishSegment(), true /* front */, true /* isOutgoing */); m_startToFinishDistanceM = ms::DistanceOnEarth(startPoint, finishPoint); } @@ -88,8 +88,8 @@ void IndexGraphStarter::Append(FakeEdgesContainer const & container) // It's important to calculate distance after m_fake.Append() because // we don't have finish segment in fake graph before m_fake.Append(). - auto const startPoint = GetPoint(GetStartSegment(), false /* front */); - auto const finishPoint = GetPoint(GetFinishSegment(), true /* front */); + auto const startPoint = GetPoint(GetStartSegment(), false /* front */, true /* isOutgoing */); + auto const finishPoint = GetPoint(GetFinishSegment(), true /* front */, true /* isOutgoing */); m_startToFinishDistanceM = ms::DistanceOnEarth(startPoint, finishPoint); m_fakeNumerationStart += container.m_fake.GetSize(); } @@ -116,50 +116,52 @@ bool IndexGraphStarter::ConvertToReal(Segment & segment) const return m_fake.FindReal(Segment(segment), segment); } -LatLonWithAltitude const & IndexGraphStarter::GetJunction(Segment const & segment, bool front) const +LatLonWithAltitude const & IndexGraphStarter::GetJunction(Segment const & segment, bool front, + bool isOutgoing) const { if (IsGuidesSegment(segment)) return m_guides.GetJunction(segment, front); if (!IsFakeSegment(segment)) - return m_graph.GetJunction(segment, front); + return m_graph.GetJunction(segment, front, isOutgoing); auto const & vertex = m_fake.GetVertex(segment); return front ? vertex.GetJunctionTo() : vertex.GetJunctionFrom(); } -LatLonWithAltitude const & IndexGraphStarter::GetRouteJunction( - vector const & segments, size_t pointIndex) const +LatLonWithAltitude const & IndexGraphStarter::GetRouteJunction(vector const & segments, + size_t pointIndex, + bool isOutgoing) const { CHECK(!segments.empty(), ()); CHECK_LESS_OR_EQUAL( pointIndex, segments.size(), ("Point with index", pointIndex, "does not exist in route with size", segments.size())); if (pointIndex == segments.size()) - return GetJunction(segments[pointIndex - 1], true /* front */); - return GetJunction(segments[pointIndex], false); + return GetJunction(segments[pointIndex - 1], true /* front */, isOutgoing); + return GetJunction(segments[pointIndex], false, isOutgoing); } -ms::LatLon const & IndexGraphStarter::GetPoint(Segment const & segment, bool front) const +ms::LatLon const & IndexGraphStarter::GetPoint(Segment const & segment, bool front, bool isOutgoing) const { - return GetJunction(segment, front).GetLatLon(); + return GetJunction(segment, front, isOutgoing).GetLatLon(); } -bool IndexGraphStarter::IsRoutingOptionsGood(Segment const & segment) const +bool IndexGraphStarter::IsRoutingOptionsGood(Segment const & segment, bool isOutgoing) const { - return m_graph.IsRoutingOptionsGood(segment); + return m_graph.IsRoutingOptionsGood(segment, isOutgoing); } -RoutingOptions IndexGraphStarter::GetRoutingOptions(Segment const & segment) const +RoutingOptions IndexGraphStarter::GetRoutingOptions(Segment const & segment, bool isOutgoing) const { if (segment.IsRealSegment()) - return m_graph.GetRoutingOptions(segment); + return m_graph.GetRoutingOptions(segment, isOutgoing); Segment real; if (!m_fake.FindReal(segment, real)) return {}; - return m_graph.GetRoutingOptions(real); + return m_graph.GetRoutingOptions(real, isOutgoing); } set IndexGraphStarter::GetMwms() const @@ -206,15 +208,17 @@ void IndexGraphStarter::GetEdgesList(astar::VertexData const & v // Weight used only when isOutgoing = false for passing to m_guides and placing to |edges|. RouteWeight ingoingSegmentWeight; if (!isOutgoing) - ingoingSegmentWeight = CalcSegmentWeight(segment, EdgeEstimator::Purpose::Weight); + ingoingSegmentWeight = CalcSegmentWeight(segment, EdgeEstimator::Purpose::Weight, isOutgoing); if (IsFakeSegment(segment)) { Segment real; if (m_fake.FindReal(segment, real)) { - bool const haveSameFront = GetJunction(segment, true /* front */) == GetJunction(real, true); - bool const haveSameBack = GetJunction(segment, false /* front */) == GetJunction(real, false); + bool const haveSameFront = + GetJunction(segment, true /* front */, isOutgoing) == GetJunction(real, true, isOutgoing); + bool const haveSameBack = + GetJunction(segment, false /* front */, isOutgoing) == GetJunction(real, false, isOutgoing); if ((isOutgoing && haveSameFront) || (!isOutgoing && haveSameBack)) { if (IsGuidesSegment(real)) @@ -232,7 +236,7 @@ void IndexGraphStarter::GetEdgesList(astar::VertexData const & v for (auto const & s : m_fake.GetEdges(segment, isOutgoing)) { - edges.emplace_back(s, isOutgoing ? CalcSegmentWeight(s, EdgeEstimator::Purpose::Weight) + edges.emplace_back(s, isOutgoing ? CalcSegmentWeight(s, EdgeEstimator::Purpose::Weight, isOutgoing) : ingoingSegmentWeight); } } @@ -260,13 +264,13 @@ RouteWeight IndexGraphStarter::CalcGuidesSegmentWeight(Segment const & segment, } RouteWeight IndexGraphStarter::CalcSegmentWeight(Segment const & segment, - EdgeEstimator::Purpose purpose) const + EdgeEstimator::Purpose purpose, bool isOutgoing) const { if (IsGuidesSegment(segment)) return CalcGuidesSegmentWeight(segment, purpose); if (!IsFakeSegment(segment)) - return m_graph.CalcSegmentWeight(segment, purpose); + return m_graph.CalcSegmentWeight(segment, purpose, isOutgoing); auto const & vertex = m_fake.GetVertex(segment); Segment real; @@ -274,7 +278,7 @@ RouteWeight IndexGraphStarter::CalcSegmentWeight(Segment const & segment, { auto const partLen = ms::DistanceOnEarth(vertex.GetPointFrom(), vertex.GetPointTo()); auto const fullLen = - ms::DistanceOnEarth(GetPoint(real, false /* front */), GetPoint(real, true /* front */)); + ms::DistanceOnEarth(GetPoint(real, false /* front */, isOutgoing), GetPoint(real, true /* front */, isOutgoing)); // Note 1. |fullLen| == 0.0 in case of Segment(s) with the same ends. // Note 2. There is the following logic behind |return 0.0 * m_graph.CalcSegmentWeight(real, ...);|: // it's necessary to return a instance of the structure |RouteWeight| with zero wight. @@ -282,7 +286,7 @@ RouteWeight IndexGraphStarter::CalcSegmentWeight(Segment const & segment, // may be kept in it and it is up to |RouteWeight| to know how to multiply by zero. Weight const weight = IsGuidesSegment(real) ? CalcGuidesSegmentWeight(real, purpose) - : m_graph.CalcSegmentWeight(real, purpose); + : m_graph.CalcSegmentWeight(real, purpose, isOutgoing); if (fullLen == 0.0) return 0.0 * weight; @@ -296,7 +300,7 @@ double IndexGraphStarter::CalculateETA(Segment const & from, Segment const & to) { // We don't distinguish fake segment weight and fake segment transit time. if (IsFakeSegment(to)) - return CalcSegmentWeight(to, EdgeEstimator::Purpose::ETA).GetWeight(); + return CalcSegmentWeight(to, EdgeEstimator::Purpose::ETA, true).GetWeight(); if (IsFakeSegment(from)) return CalculateETAWithoutPenalty(to); @@ -323,7 +327,7 @@ double IndexGraphStarter::CalculateETA(Segment const & from, Segment const & to) double IndexGraphStarter::CalculateETAWithoutPenalty(Segment const & segment) const { if (IsFakeSegment(segment)) - return CalcSegmentWeight(segment, EdgeEstimator::Purpose::ETA).GetWeight(); + return CalcSegmentWeight(segment, EdgeEstimator::Purpose::ETA, true).GetWeight(); if (IsGuidesSegment(segment)) return CalcGuidesSegmentWeight(segment, EdgeEstimator::Purpose::ETA).GetWeight(); @@ -534,18 +538,18 @@ void IndexGraphStarter::AddFakeEdges(Segment const & segment, bool isOutgoing, v // |segment| |s| // *------------>*-----------> bool const sIsOutgoing = - GetJunction(segment, true /* front */) == GetJunction(s, false /* front */); + GetJunction(segment, true /* front */, false) == GetJunction(s, false /* front */, false); // |s| |segment| // *------------>*-----------> bool const sIsIngoing = - GetJunction(s, true /* front */) == GetJunction(segment, false /* front */); + GetJunction(s, true /* front */, false) == GetJunction(segment, false /* front */, false); if ((isOutgoing && sIsOutgoing) || (!isOutgoing && sIsIngoing)) { // For ingoing edges we use source weight which is the same for |s| and for |edge| and is // already calculated. - fakeEdges.emplace_back(s, isOutgoing ? CalcSegmentWeight(s, EdgeEstimator::Purpose::Weight) + fakeEdges.emplace_back(s, isOutgoing ? CalcSegmentWeight(s, EdgeEstimator::Purpose::Weight, isOutgoing) : edge.GetWeight()); } } @@ -586,6 +590,6 @@ RouteWeight IndexGraphStarter::GetAStarWeightEpsilon() // distinguish the point geometry changing in |kMwmPointAccuracy| radius of the same segments from // mwms with different versions. So let's use such epsilon to maintain the A* invariant. return kEps + - m_graph.HeuristicCostEstimate(ms::LatLon(0.0, 0.0), ms::LatLon(0.0, kMwmPointAccuracy)); + m_graph.HeuristicCostEstimate(ms::LatLon(0.0, 0.0), ms::LatLon(0.0, kMwmPointAccuracy), true); } } // namespace routing diff --git a/routing/index_graph_starter.hpp b/routing/index_graph_starter.hpp index 88172a558e7..88851794b7b 100644 --- a/routing/index_graph_starter.hpp +++ b/routing/index_graph_starter.hpp @@ -73,13 +73,14 @@ class IndexGraphStarter : public AStarGraph const & route, - size_t pointIndex) const; - ms::LatLon const & GetPoint(Segment const & segment, bool front) const; + LatLonWithAltitude const & GetJunction(Segment const & segment, bool front, + bool isOutgoing) const; + LatLonWithAltitude const & GetRouteJunction(std::vector const & segments, size_t pointIndex, + bool isOutgoing) const; + ms::LatLon const & GetPoint(Segment const & segment, bool front, bool isOutgoing) const; - bool IsRoutingOptionsGood(Segment const & segment) const; - RoutingOptions GetRoutingOptions(Segment const & segment) const; + bool IsRoutingOptionsGood(Segment const & segment, bool isOutgoing) const; + RoutingOptions GetRoutingOptions(Segment const & segment, bool isOutgoing) const; uint32_t GetNumFakeSegments() const { @@ -119,10 +120,10 @@ class IndexGraphStarter : public AStarGraph & parents) override @@ -149,12 +150,12 @@ class IndexGraphStarter : public AStarGraph #include #include +#include #include #include #include @@ -40,13 +41,13 @@ class IndexGraphStarterJoints : public AStarGraph const & vertexData, std::vector & edges) override @@ -184,6 +185,8 @@ class IndexGraphStarterJoints : public AStarGraph m_savedWeight; // JointSegment consists of two segments of one feature. @@ -209,8 +213,11 @@ class IndexGraphStarterJoints : public AStarGraph m_path; }; + std::mutex m_reconstructedFakeJointsMtx; std::map m_reconstructedFakeJoints; + // |m_startOutEdges| and |m_endOutEdges| are filled on initialization stage. + // So they may be used without any synchronization. // List of JointEdges that are outgoing from start. std::vector m_startOutEdges; // List of incoming to finish. @@ -259,7 +266,7 @@ void IndexGraphStarterJoints::InitEnding(Segment const & ending, bool sta segment = ending; auto & point = start ? m_startPoint : m_endPoint; - point = m_graph.GetPoint(ending, true /* front */); + point = m_graph.GetPoint(ending, true /* front */, true /* isOutgoing */); auto & endingJoint = start ? m_startJoint : m_endJoint; if (IsRealSegment(ending)) @@ -272,13 +279,17 @@ void IndexGraphStarterJoints::InitEnding(Segment const & ending, bool sta endingJoint = CreateFakeJoint(loopSegment, loopSegment); } - m_reconstructedFakeJoints[endingJoint] = ReconstructedPath({ending}, start); + { + std::lock_guard guard(m_reconstructedFakeJointsMtx); + m_reconstructedFakeJoints[endingJoint] = ReconstructedPath({ending}, start); + } auto & outEdges = start ? m_startOutEdges : m_endOutEdges; outEdges = FindFirstJoints(ending, start); if (!start) { +// std::lock_guard guard(m_savedWeightMtx); // Initialization before starting two threads. m_savedWeight[m_endJoint] = Weight(0.0); for (auto const & edge : m_endOutEdges) m_savedWeight[edge.GetTarget()] = edge.GetWeight(); @@ -287,7 +298,7 @@ void IndexGraphStarterJoints::InitEnding(Segment const & ending, bool sta template RouteWeight IndexGraphStarterJoints::HeuristicCostEstimate(JointSegment const & from, - JointSegment const & to) + JointSegment const & to, bool isOutgoing) { ASSERT(to == m_startJoint || to == m_endJoint, ("Invariant violated.")); bool toEnd = to == m_endJoint; @@ -295,6 +306,7 @@ RouteWeight IndexGraphStarterJoints::HeuristicCostEstimate(JointSegment c Segment fromSegment; if (from.IsFake() || IsInvisible(from)) { + std::lock_guard guard(m_reconstructedFakeJointsMtx); ASSERT_NOT_EQUAL(m_reconstructedFakeJoints.count(from), 0, ()); fromSegment = m_reconstructedFakeJoints[from].m_path.back(); } @@ -303,18 +315,18 @@ RouteWeight IndexGraphStarterJoints::HeuristicCostEstimate(JointSegment c fromSegment = from.GetSegment(false /* start */); } - return toEnd ? m_graph.HeuristicCostEstimate(fromSegment, m_endPoint) - : m_graph.HeuristicCostEstimate(fromSegment, m_startPoint); + return toEnd ? m_graph.HeuristicCostEstimate(fromSegment, m_endPoint, isOutgoing) + : m_graph.HeuristicCostEstimate(fromSegment, m_startPoint, isOutgoing); } template ms::LatLon const & -IndexGraphStarterJoints::GetPoint(JointSegment const & jointSegment, bool start) +IndexGraphStarterJoints::GetPoint(JointSegment const & jointSegment, bool start, bool isOutgoing) { Segment segment = jointSegment.IsFake() ? m_fakeJointSegments[jointSegment].GetSegment(start) : jointSegment.GetSegment(start); - return m_graph.GetPoint(segment, jointSegment.IsForward()); + return m_graph.GetPoint(segment, jointSegment.IsForward(), isOutgoing); } template @@ -328,11 +340,15 @@ std::vector IndexGraphStarterJoints::ReconstructJoint(JointSegme // In case of a fake vertex we return its prebuilt path. if (joint.IsFake()) { - auto const it = m_reconstructedFakeJoints.find(joint); - CHECK(it != m_reconstructedFakeJoints.cend(), ("Can not find such fake joint")); + std::vector path; + { + std::lock_guard guard(m_reconstructedFakeJointsMtx); + auto const it = m_reconstructedFakeJoints.find(joint); + CHECK(it != m_reconstructedFakeJoints.cend(), ("Can not find such fake joint")); + path = it->second.m_path; + ASSERT(!path.empty(), ()); + } - auto path = it->second.m_path; - ASSERT(!path.empty(), ()); if (path.front() == m_startSegment && path.back() == m_endSegment) path.pop_back(); @@ -423,6 +439,7 @@ std::optional IndexGraphStarterJoints::GetParentSegment( } else { +// std::lock_guard guard(m_savedWeightMtx); auto const it = m_savedWeight.find(vertex); CHECK(it != m_savedWeight.cend(), ("Can not find weight for:", vertex)); @@ -527,6 +544,9 @@ void IndexGraphStarterJoints::GetEdgeList( // |parentSegment| is parent-vertex from which we search children. // For correct weight calculation we should get weight of JointSegment, that // ends in |parentSegment| and add |parentWeight[i]| to the saved value. + + // @TODO It seems this guards is taken too often. +// std::lock_guard guard(m_savedWeightMtx); auto const it = m_savedWeight.find(vertex); CHECK(it != m_savedWeight.cend(), ("Can not find weight for:", vertex)); @@ -609,6 +629,7 @@ std::vector IndexGraphStarterJoints::FindFirstJoints(Segment c result.emplace_back(fakeJoint, weight[beforeConvert]); std::vector path = reconstructPath(beforeConvert, fromStart); + std::lock_guard guard(m_reconstructedFakeJointsMtx); m_reconstructedFakeJoints.emplace(fakeJoint, ReconstructedPath(std::move(path), fromStart)); }; @@ -618,10 +639,10 @@ std::vector IndexGraphStarterJoints::FindFirstJoints(Segment c CHECK(!IsRealSegment(fake), ()); bool const hasSameFront = - m_graph.GetPoint(fake, true /* front */) == m_graph.GetPoint(segment, true); + m_graph.GetPoint(fake, true /* front */, true /* isOutgoing */) == m_graph.GetPoint(segment, true, true /* isOutgoing */); bool const hasSameBack = - m_graph.GetPoint(fake, false /* front */) == m_graph.GetPoint(segment, false); + m_graph.GetPoint(fake, false /* front */, true /* isOutgoing */) == m_graph.GetPoint(segment, false, true /* isOutgoing */); return (fromStart && hasSameFront) || (!fromStart && hasSameBack); }; @@ -683,9 +704,15 @@ void IndexGraphStarterJoints::Reset() m_endJoint = JointSegment(); m_startSegment = Segment(); m_endSegment = Segment(); - m_savedWeight.clear(); + { +// std::lock_guard guard(m_savedWeightMtx); + m_savedWeight.clear(); + } m_fakeJointSegments.clear(); - m_reconstructedFakeJoints.clear(); + { + std::lock_guard guard(m_reconstructedFakeJointsMtx); + m_reconstructedFakeJoints.clear(); + } m_startOutEdges.clear(); m_endOutEdges.clear(); m_fakeId = 0; diff --git a/routing/index_road_graph.cpp b/routing/index_road_graph.cpp index b60a8083385..b2751f0d425 100644 --- a/routing/index_road_graph.cpp +++ b/routing/index_road_graph.cpp @@ -98,9 +98,9 @@ void IndexRoadGraph::GetRouteEdges(EdgeVector & edges) const for (Segment const & segment : m_segments) { auto const & junctionFrom = - m_starter.GetJunction(segment, false /* front */).ToPointWithAltitude(); + m_starter.GetJunction(segment, false /* front */, true /* isOutgoing */).ToPointWithAltitude(); auto const & junctionTo = - m_starter.GetJunction(segment, true /* front */).ToPointWithAltitude(); + m_starter.GetJunction(segment, true /* front */, true /* isOutgoing */).ToPointWithAltitude(); if (IndexGraphStarter::IsFakeSegment(segment) || TransitGraph::IsTransitSegment(segment)) { @@ -160,8 +160,8 @@ void IndexRoadGraph::GetEdges(geometry::PointWithAltitude const & junction, bool edges.push_back(Edge::MakeReal( FeatureID(mwmId, segment.GetFeatureId()), segment.IsForward(), segment.GetSegmentIdx(), - m_starter.GetJunction(segment, false /* front */).ToPointWithAltitude(), - m_starter.GetJunction(segment, true /* front */).ToPointWithAltitude())); + m_starter.GetJunction(segment, false /* front */, isOutgoing).ToPointWithAltitude(), + m_starter.GetJunction(segment, true /* front */, isOutgoing).ToPointWithAltitude())); } } diff --git a/routing/index_router.cpp b/routing/index_router.cpp index 90610f5c7a0..6dfda3411e8 100644 --- a/routing/index_router.cpp +++ b/routing/index_router.cpp @@ -588,14 +588,19 @@ RouterResultCode IndexRouter::DoCalculateRoute(Checkpoints const & checkpoints, TrafficStash::Guard guard(m_trafficStash); unique_ptr graph = MakeWorldGraph(); +// graph->MultithreadingIssue(m_dataSource); vector segments; vector startSegments; bool startSegmentIsAlmostCodirectionalDirection = false; - bool const foundStart = - FindBestSegments(checkpoints.GetPointFrom(), startDirection, true /* isOutgoing */, *graph, - startSegments, startSegmentIsAlmostCodirectionalDirection); + bool foundStart = false; + { + base::ScopedTimerWithLog timer("MTR FindBestSegments"); + foundStart = + FindBestSegments(checkpoints.GetPointFrom(), startDirection, true /* isOutgoing */, *graph, + startSegments, startSegmentIsAlmostCodirectionalDirection); + } m_guides.SetGuidesGraphParams(guidesMwmId, m_estimator->GetMaxWeightSpeedMpS()); m_guides.ConnectToGuidesGraph(checkpoints.GetPoints()); @@ -629,15 +634,18 @@ RouterResultCode IndexRouter::DoCalculateRoute(Checkpoints const & checkpoints, vector finishSegments; bool dummy = false; - // Stop building route if |finishCheckpoint| is not connected to OSM and is not connected to - // the guides graph. - if (!FindBestSegments(finishCheckpoint, m2::PointD::Zero() /* direction */, - false /* isOutgoing */, *graph, finishSegments, - dummy /* bestSegmentIsAlmostCodirectional */) && - finishFakeEnding.m_projections.empty()) { - return isLastSubroute ? RouterResultCode::EndPointNotFound - : RouterResultCode::IntermediatePointNotFound; + base::ScopedTimerWithLog timer("MTR Find finish or intermediate segment."); + // Stop building route if |finishCheckpoint| is not connected to OSM and is not connected to + // the guides graph. + if (!FindBestSegments(finishCheckpoint, m2::PointD::Zero() /* direction */, + false /* isOutgoing */, *graph, finishSegments, + dummy /* bestSegmentIsAlmostCodirectional */) && + finishFakeEnding.m_projections.empty()) + { + return isLastSubroute ? RouterResultCode::EndPointNotFound + : RouterResultCode::IntermediatePointNotFound; + } } bool isStartSegmentStrictForward = (m_vehicleType == VehicleType::Car); @@ -656,6 +664,8 @@ RouterResultCode IndexRouter::DoCalculateRoute(Checkpoints const & checkpoints, starter ? starter->GetNumFakeSegments() + startIdx : startIdx; IndexGraphStarter subrouteStarter(startFakeEnding, finishFakeEnding, fakeNumerationStart, isStartSegmentStrictForward, *graph); + IndexGraphStarter subrouteStarterBwd(startFakeEnding, finishFakeEnding, fakeNumerationStart, + isStartSegmentStrictForward, *graph); if (m_guides.IsAttached()) { @@ -676,7 +686,7 @@ RouterResultCode IndexRouter::DoCalculateRoute(Checkpoints const & checkpoints, progress->AppendSubProgress(subProgress); SCOPE_GUARD(eraseProgress, [&progress]() { progress->PushAndDropLastSubProgress(); }); - auto const result = CalculateSubroute(checkpoints, i, delegate, progress, subrouteStarter, + auto const result = CalculateSubroute(checkpoints, i, delegate, progress, subrouteStarter, subrouteStarterBwd, subroute, m_guides.IsAttached()); if (result != RouterResultCode::NoError) @@ -710,7 +720,12 @@ RouterResultCode IndexRouter::DoCalculateRoute(Checkpoints const & checkpoints, // TODO (@gmoryes) https://jira.mail.ru/browse/MAPSME-10694 // We should do RedressRoute for each subroute separately. - auto redressResult = RedressRoute(segments, delegate.GetCancellable(), *starter, route); + RouterResultCode redressResult = RouterResultCode::InternalError; + + { + base::ScopedTimerWithLog timer("MTR RedressRoute."); + redressResult = RedressRoute(segments, delegate.GetCancellable(), *starter, route); + } if (redressResult != RouterResultCode::NoError) return redressResult; @@ -720,7 +735,7 @@ RouterResultCode IndexRouter::DoCalculateRoute(Checkpoints const & checkpoints, m_lastRoute = make_unique(checkpoints.GetStart(), checkpoints.GetFinish(), route.GetSubroutes()); for (Segment const & segment : segments) - m_lastRoute->AddStep(segment, mercator::FromLatLon(starter->GetPoint(segment, true /* front */))); + m_lastRoute->AddStep(segment, mercator::FromLatLon(starter->GetPoint(segment, true /* front */, true /* isOutgoing */))); m_lastFakeEdges = make_unique(move(*starter)); @@ -757,6 +772,7 @@ RouterResultCode IndexRouter::CalculateSubroute(Checkpoints const & checkpoints, RouterDelegate const & delegate, shared_ptr const & progress, IndexGraphStarter & starter, + IndexGraphStarter & starterBwd, vector & subroute, bool guidesActive /* = false */) { @@ -764,6 +780,7 @@ RouterResultCode IndexRouter::CalculateSubroute(Checkpoints const & checkpoints, subroute.clear(); SetupAlgorithmMode(starter, guidesActive); + SetupAlgorithmMode(starterBwd, guidesActive); LOG(LINFO, ("Routing in mode:", starter.GetGraph().GetMode())); base::ScopedTimerWithLog timer("Route build"); @@ -771,11 +788,11 @@ RouterResultCode IndexRouter::CalculateSubroute(Checkpoints const & checkpoints, switch (mode) { case WorldGraphMode::Joints: - return CalculateSubrouteJointsMode(starter, delegate, progress, subroute); + return CalculateSubrouteJointsMode(starter, starterBwd, delegate, progress, subroute); case WorldGraphMode::NoLeaps: - return CalculateSubrouteNoLeapsMode(starter, delegate, progress, subroute); + return CalculateSubrouteNoLeapsMode(starter, starterBwd, delegate, progress, subroute); case WorldGraphMode::LeapsOnly: - return CalculateSubrouteLeapsOnlyMode(checkpoints, subrouteIdx, starter, delegate, progress, + return CalculateSubrouteLeapsOnlyMode(checkpoints, subrouteIdx, starter, starterBwd, delegate, progress, subroute); default: CHECK(false, ("Wrong WorldGraphMode here:", mode)); } @@ -783,11 +800,12 @@ RouterResultCode IndexRouter::CalculateSubroute(Checkpoints const & checkpoints, } RouterResultCode IndexRouter::CalculateSubrouteJointsMode( - IndexGraphStarter & starter, RouterDelegate const & delegate, + IndexGraphStarter & starter, IndexGraphStarter & starterBwd, RouterDelegate const & delegate, shared_ptr const & progress, vector & subroute) { using JointsStarter = IndexGraphStarterJoints; JointsStarter jointStarter(starter, starter.GetStartSegment(), starter.GetFinishSegment()); + JointsStarter jointStarterBwd(starterBwd, starterBwd.GetStartSegment(), starterBwd.GetFinishSegment()); using Visitor = JunctionVisitor; Visitor visitor(jointStarter, delegate, kVisitPeriod, progress); @@ -797,13 +815,17 @@ RouterResultCode IndexRouter::CalculateSubrouteJointsMode( using Weight = JointsStarter::Weight; AStarAlgorithm::Params params( - jointStarter, jointStarter.GetStartJoint(), jointStarter.GetFinishJoint(), + jointStarter, jointStarterBwd, jointStarter.GetStartJoint(), jointStarter.GetFinishJoint(), nullptr /* prevRoute */, delegate.GetCancellable(), move(visitor), AStarLengthChecker(starter)); + RouterResultCode result = RouterResultCode::InternalError; RoutingResult routingResult; - RouterResultCode const result = - FindPath(params, {} /* mwmIds */, routingResult, WorldGraphMode::Joints); + { + base::ScopedTimerWithLog timer("MTR CalculateSubrouteJointsMode"); + result = FindPath( + params, {} /* mwmIds */, routingResult, WorldGraphMode::Joints); + } if (result != RouterResultCode::NoError) return result; @@ -813,7 +835,7 @@ RouterResultCode IndexRouter::CalculateSubrouteJointsMode( } RouterResultCode IndexRouter::CalculateSubrouteNoLeapsMode( - IndexGraphStarter & starter, RouterDelegate const & delegate, + IndexGraphStarter & starter, IndexGraphStarter & starterBwd, RouterDelegate const & delegate, shared_ptr const & progress, vector & subroute) { using Vertex = IndexGraphStarter::Vertex; @@ -824,7 +846,7 @@ RouterResultCode IndexRouter::CalculateSubrouteNoLeapsMode( Visitor visitor(starter, delegate, kVisitPeriod, progress); AStarAlgorithm::Params params( - starter, starter.GetStartSegment(), starter.GetFinishSegment(), nullptr /* prevRoute */, + starter, starterBwd, starter.GetStartSegment(), starter.GetFinishSegment(), nullptr /* prevRoute */, delegate.GetCancellable(), move(visitor), AStarLengthChecker(starter)); RoutingResult routingResult; @@ -841,10 +863,11 @@ RouterResultCode IndexRouter::CalculateSubrouteNoLeapsMode( RouterResultCode IndexRouter::CalculateSubrouteLeapsOnlyMode( Checkpoints const & checkpoints, size_t subrouteIdx, IndexGraphStarter & starter, - RouterDelegate const & delegate, shared_ptr const & progress, + IndexGraphStarter & starterBwd, RouterDelegate const & delegate, shared_ptr const & progress, vector & subroute) { LeapsGraph leapsGraph(starter, MwmHierarchyHandler(m_numMwmIds, m_countryParentNameGetterFn)); + LeapsGraph leapsGraphBwd(starterBwd, MwmHierarchyHandler(m_numMwmIds, m_countryParentNameGetterFn)); using Vertex = LeapsGraph::Vertex; using Edge = LeapsGraph::Edge; @@ -859,13 +882,17 @@ RouterResultCode IndexRouter::CalculateSubrouteLeapsOnlyMode( Visitor visitor(leapsGraph, delegate, kVisitPeriodForLeaps, progress); AStarAlgorithm::Params params( - leapsGraph, leapsGraph.GetStartSegment(), leapsGraph.GetFinishSegment(), + leapsGraph, leapsGraphBwd, leapsGraph.GetStartSegment(), leapsGraph.GetFinishSegment(), nullptr /* prevRoute */, delegate.GetCancellable(), move(visitor), AStarLengthChecker(starter)); + RouterResultCode result; RoutingResult routingResult; - RouterResultCode const result = - FindPath(params, {} /* mwmIds */, routingResult, WorldGraphMode::LeapsOnly); + { + base::ScopedTimerWithLog timer("MTR Cross mwm FindPath."); + result = FindPath( + params, {} /* mwmIds */, routingResult, WorldGraphMode::LeapsOnly); + } progress->PushAndDropLastSubProgress(); @@ -924,7 +951,7 @@ RouterResultCode IndexRouter::AdjustRoute(Checkpoints const & checkpoints, { auto const & step = steps[i]; prevEdges.emplace_back(step.GetSegment(), starter.CalcSegmentWeight(step.GetSegment(), - EdgeEstimator::Purpose::Weight)); + EdgeEstimator::Purpose::Weight, true)); } using Visitor = JunctionVisitor; @@ -935,8 +962,10 @@ RouterResultCode IndexRouter::AdjustRoute(Checkpoints const & checkpoints, using Weight = IndexGraphStarter::Weight; AStarAlgorithm algorithm; + // @TODO Duplicate starter. + CHECK(false, ("Duplicate stater.")); AStarAlgorithm::Params params( - starter, starter.GetStartSegment(), {} /* finalVertex */, &prevEdges, + starter, starter, starter.GetStartSegment(), {} /* finalVertex */, &prevEdges, delegate.GetCancellable(), move(visitor), AdjustLengthChecker(starter)); RoutingResult result; @@ -1006,7 +1035,7 @@ unique_ptr IndexRouter::MakeWorldGraph() { auto graph = make_unique( move(crossMwmGraph), move(indexGraphLoader), m_estimator, - MwmHierarchyHandler(m_numMwmIds, m_countryParentNameGetterFn)); + MwmHierarchyHandler(m_numMwmIds, m_countryParentNameGetterFn), m_numMwmIds); graph->SetRoutingOptions(routingOptions); return graph; } @@ -1333,8 +1362,8 @@ RouterResultCode IndexRouter::ProcessLeapsJoints(vector const & input, maxStart = max(maxStart, start); auto const contribCoef = static_cast(end - maxStart + 1) / (input.size()); - auto const startPoint = starter.GetPoint(input[start], true /* front */); - auto const endPoint = starter.GetPoint(input[end], true /* front */); + auto const startPoint = starter.GetPoint(input[start], true /* front */, true /* isOutgoing */); + auto const endPoint = starter.GetPoint(input[end], true /* front */, true /* isOutgoing */); progress->AppendSubProgress({startPoint, endPoint, contribCoef}); RouterResultCode resultCode = RouterResultCode::NoError; @@ -1348,12 +1377,17 @@ RouterResultCode IndexRouter::ProcessLeapsJoints(vector const & input, using Visitor = JunctionVisitor; Visitor visitor(jointStarter, delegate, kVisitPeriod, progress); + // @TODO Duplicate jointStarter. + CHECK(false, ("Duplicate jointStarter.")); AStarAlgorithm::Params params( - jointStarter, jointStarter.GetStartJoint(), jointStarter.GetFinishJoint(), + jointStarter, jointStarter, jointStarter.GetStartJoint(), jointStarter.GetFinishJoint(), nullptr /* prevRoute */, delegate.GetCancellable(), move(visitor), AStarLengthChecker(starter)); - resultCode = FindPath(params, mwmIds, routingResult, mode); + { + base::ScopedTimerWithLog timer("MTR In one mwm after cross mwm."); + resultCode = FindPath(params, mwmIds, routingResult, mode); + } return resultCode; }; @@ -1381,8 +1415,8 @@ RouterResultCode IndexRouter::ProcessLeapsJoints(vector const & input, } LOG(LINFO, ("Can not find path", - "from:", starter.GetPoint(input[start], input[start].IsForward()), - "to:", starter.GetPoint(input[end], input[end].IsForward()))); + "from:", starter.GetPoint(input[start], input[start].IsForward(), true /* isOutgoing */), + "to:", starter.GetPoint(input[end], input[end].IsForward(), true /* isOutgoing */))); return false; }; @@ -1412,12 +1446,12 @@ RouterResultCode IndexRouter::ProcessLeapsJoints(vector const & input, if (!tryBuildRoute(prev, next, WorldGraphMode::JointSingleMwm, routingResult)) { - auto const prevPoint = starter.GetPoint(input[next], true); + auto const prevPoint = starter.GetPoint(input[next], true, true /* isOutgoing */); // |next + 1| - is the twin of |next| // |next + 2| - is the next exit. while (next + 2 < finishLeapStart && next != finishLeapStart) { - auto const point = starter.GetPoint(input[next + 2], true); + auto const point = starter.GetPoint(input[next + 2], true, true /* isOutgoing */); double const distBetweenExistsMeters = ms::DistanceOnEarth(point, prevPoint); static double constexpr kMinDistBetweenExitsM = 100000; // 100 km @@ -1476,7 +1510,7 @@ RouterResultCode IndexRouter::RedressRoute(vector const & segments, junctions.reserve(numPoints); for (size_t i = 0; i < numPoints; ++i) - junctions.emplace_back(starter.GetRouteJunction(segments, i).ToPointWithAltitude()); + junctions.emplace_back(starter.GetRouteJunction(segments, i, true /* isOutgoing */).ToPointWithAltitude()); IndexRoadGraph roadGraph(m_numMwmIds, starter, segments, junctions, m_dataSource); starter.GetGraph().SetMode(WorldGraphMode::NoLeaps); @@ -1513,7 +1547,7 @@ RouterResultCode IndexRouter::RedressRoute(vector const & segments, // to use them. if (m_vehicleType == VehicleType::Car) { - routeSegment.SetRoadTypes(starter.GetRoutingOptions(segment)); + routeSegment.SetRoadTypes(starter.GetRoutingOptions(segment, true /* isOutgoing */)); if (segment.IsRealSegment() && !AreSpeedCamerasProhibited(m_numMwmIds->GetFile(segment.GetMwmId()))) { @@ -1610,6 +1644,7 @@ void IndexRouter::FillSpeedCamProhibitedMwms(vector const & segments, } } +// @TODO This method should be const. void IndexRouter::SetupAlgorithmMode(IndexGraphStarter & starter, bool guidesActive) { // We use NoLeaps for pedestrians and bicycles with route points near to the Guides tracks diff --git a/routing/index_router.hpp b/routing/index_router.hpp index a4ac4c995e8..415cea6bdbd 100644 --- a/routing/index_router.hpp +++ b/routing/index_router.hpp @@ -102,15 +102,17 @@ class IndexRouter : public IRouter private: RouterResultCode CalculateSubrouteJointsMode(IndexGraphStarter & starter, + IndexGraphStarter & starterBwd, RouterDelegate const & delegate, std::shared_ptr const & progress, std::vector & subroute); - RouterResultCode CalculateSubrouteNoLeapsMode(IndexGraphStarter & starter, + RouterResultCode CalculateSubrouteNoLeapsMode(IndexGraphStarter & starter, IndexGraphStarter & starterBwd, RouterDelegate const & delegate, std::shared_ptr const & progress, std::vector & subroute); RouterResultCode CalculateSubrouteLeapsOnlyMode(Checkpoints const & checkpoints, size_t subrouteIdx, IndexGraphStarter & starter, + IndexGraphStarter & starterBwd, RouterDelegate const & delegate, std::shared_ptr const & progress, std::vector & subroute); @@ -121,7 +123,8 @@ class IndexRouter : public IRouter RouterResultCode CalculateSubroute(Checkpoints const & checkpoints, size_t subrouteIdx, RouterDelegate const & delegate, std::shared_ptr const & progress, - IndexGraphStarter & graph, std::vector & subroute, + IndexGraphStarter & graph, IndexGraphStarter & graphBwd, + std::vector & subroute, bool guidesActive = false); RouterResultCode AdjustRoute(Checkpoints const & checkpoints, @@ -211,6 +214,7 @@ class IndexRouter : public IRouter AStarParams & params, std::set const & mwmIds, RoutingResult & routingResult, WorldGraphMode mode) const { + base::ScopedTimerWithLog timerWithLog("***FindPath***", base::ScopedTimerWithLog::Measure::Seconds); AStarAlgorithm algorithm; return ConvertTransitResult( mwmIds, ConvertResult(algorithm.FindPathBidirectional(params, routingResult))); diff --git a/routing/junction_visitor.hpp b/routing/junction_visitor.hpp index 9e09efcb443..9135fee6ab7 100644 --- a/routing/junction_visitor.hpp +++ b/routing/junction_visitor.hpp @@ -33,14 +33,14 @@ class JunctionVisitor if (m_visitCounter % m_visitPeriod != 0) return; - auto const & pointFrom = m_graph.GetPoint(from, true /* front */); + auto const & pointFrom = m_graph.GetPoint(from, true /* front */, true /* isOutgoing */); m_delegate.OnPointCheck(pointFrom); auto progress = m_progress.lock(); if (!progress) return; - auto const & pointTo = m_graph.GetPoint(to, true /* front */); + auto const & pointTo = m_graph.GetPoint(to, true /* front */, true /* isOutgoing */); auto const currentPercent = progress->UpdateProgress(pointFrom, pointTo); if (currentPercent - m_lastProgressPercent > kProgressInterval) { diff --git a/routing/leaps_graph.cpp b/routing/leaps_graph.cpp index 6a295865f52..9ed11a374b5 100644 --- a/routing/leaps_graph.cpp +++ b/routing/leaps_graph.cpp @@ -10,8 +10,8 @@ namespace routing LeapsGraph::LeapsGraph(IndexGraphStarter & starter, MwmHierarchyHandler && hierarchyHandler) : m_starter(starter), m_hierarchyHandler(std::move(hierarchyHandler)) { - m_startPoint = m_starter.GetPoint(m_starter.GetStartSegment(), true /* front */); - m_finishPoint = m_starter.GetPoint(m_starter.GetFinishSegment(), true /* front */); + m_startPoint = m_starter.GetPoint(m_starter.GetStartSegment(), true /* front */, true /* isOutgoing */); + m_finishPoint = m_starter.GetPoint(m_starter.GetFinishSegment(), true /* front */, true /* isOutgoing */); m_startSegment = m_starter.GetStartSegment(); m_finishSegment = m_starter.GetFinishSegment(); } @@ -28,12 +28,12 @@ void LeapsGraph::GetIngoingEdgesList(astar::VertexData const & v GetEdgesList(vertexData.m_vertex, false /* isOutgoing */, edges); } -RouteWeight LeapsGraph::HeuristicCostEstimate(Segment const & from, Segment const & to) +RouteWeight LeapsGraph::HeuristicCostEstimate(Segment const & from, Segment const & to, bool isOutgoing) { ASSERT(to == m_startSegment || to == m_finishSegment, ()); bool const toFinish = to == m_finishSegment; auto const & toPoint = toFinish ? m_finishPoint : m_startPoint; - return m_starter.HeuristicCostEstimate(from, toPoint); + return m_starter.HeuristicCostEstimate(from, toPoint, isOutgoing); } void LeapsGraph::GetEdgesList(Segment const & segment, bool isOutgoing, @@ -55,7 +55,7 @@ void LeapsGraph::GetEdgesList(Segment const & segment, bool isOutgoing, return GetEdgesListToFinish(segment, edges); } - if (!m_starter.IsRoutingOptionsGood(segment)) + if (!m_starter.IsRoutingOptionsGood(segment, isOutgoing)) return; auto & crossMwmGraph = m_starter.GetGraph().GetCrossMwmGraph(); @@ -86,7 +86,7 @@ void LeapsGraph::GetEdgesListFromStart(Segment const & segment, std::vector std::vector & edges) override; void GetIngoingEdgesList(astar::VertexData const & vertexData, std::vector & edges) override; - RouteWeight HeuristicCostEstimate(Segment const & from, Segment const & to) override; + RouteWeight HeuristicCostEstimate(Segment const & from, Segment const & to, bool isOutgoing) override; RouteWeight GetAStarWeightEpsilon() override; // @} Segment const & GetStartSegment() const; Segment const & GetFinishSegment() const; - ms::LatLon const & GetPoint(Segment const & segment, bool front) const; + ms::LatLon const & GetPoint(Segment const & segment, bool front, bool isOutgoing) const; private: void GetEdgesList(Segment const & segment, bool isOutgoing, std::vector & edges); diff --git a/routing/restriction_loader.cpp b/routing/restriction_loader.cpp index 24d51a17be0..19bc8eaa16f 100644 --- a/routing/restriction_loader.cpp +++ b/routing/restriction_loader.cpp @@ -162,7 +162,7 @@ void ConvertRestrictionsOnlyUTurnToNo(IndexGraph & graph, if (!graph.IsRoad(featureId)) continue; - uint32_t const n = graph.GetGeometry().GetRoad(featureId).GetPointsCount(); + uint32_t const n = graph.GetGeometry().GetRoad(featureId, true).GetPointsCount(); // !!! RoadJointIds const & joints = graph.GetRoad(uTurnRestriction.m_featureId); Joint::Id const joint = uTurnRestriction.m_viaIsFirstPoint ? joints.GetJointId(0) : joints.GetJointId(n - 1); diff --git a/routing/routing_tests/index_graph_test.cpp b/routing/routing_tests/index_graph_test.cpp index 759948b037b..79c6d6ae85a 100644 --- a/routing/routing_tests/index_graph_test.cpp +++ b/routing/routing_tests/index_graph_test.cpp @@ -81,7 +81,7 @@ void TestRoute(FakeEnding const & start, FakeEnding const & finish, size_t expec void TestEdges(IndexGraph & graph, Segment const & segment, vector const & expectedTargets, bool isOutgoing) { - ASSERT(segment.IsForward() || !graph.GetGeometry().GetRoad(segment.GetFeatureId()).IsOneWay(), + ASSERT(segment.IsForward() || !graph.GetGeometry().GetRoad(segment.GetFeatureId(), isOutgoing).IsOneWay(), ()); vector edges; diff --git a/routing/routing_tests/index_graph_tools.cpp b/routing/routing_tests/index_graph_tools.cpp index c25f645a31e..7a659003171 100644 --- a/routing/routing_tests/index_graph_tools.cpp +++ b/routing/routing_tests/index_graph_tools.cpp @@ -91,7 +91,7 @@ void NoUTurnRestrictionTest::TestRouteGeom(Segment const & start, Segment const for (size_t i = 0; i < routingResult.m_path.size(); ++i) { static auto constexpr kEps = 1e-3; - auto const point = m_graph->GetWorldGraph().GetPoint(routingResult.m_path[i], true /* forward */); + auto const point = m_graph->GetWorldGraph().GetPoint(routingResult.m_path[i], true /* forward */, true); if (!base::AlmostEqualAbs(mercator::FromLatLon(point), expectedRouteGeom[i], kEps)) { TEST(false, ("Coords missmated at index:", i, "expected:", expectedRouteGeom[i], @@ -101,7 +101,7 @@ void NoUTurnRestrictionTest::TestRouteGeom(Segment const & start, Segment const } // ZeroGeometryLoader ------------------------------------------------------------------------------ -void ZeroGeometryLoader::Load(uint32_t /* featureId */, routing::RoadGeometry & road) +void ZeroGeometryLoader::Load(uint32_t /* featureId */, bool isOutgoing, routing::RoadGeometry & road) { // Any valid road will do. auto const points = routing::RoadGeometry::Points({{0.0, 0.0}, {0.0, 1.0}}); @@ -137,7 +137,7 @@ void TestTransitGraphLoader::AddGraph(NumMwmId mwmId, unique_ptr g // WeightedEdgeEstimator -------------------------------------------------------------- double WeightedEdgeEstimator::CalcSegmentWeight(Segment const & segment, RoadGeometry const & /* road */, - EdgeEstimator::Purpose /* purpose */) const + EdgeEstimator::Purpose /* purpose */, bool isOutgoing) const { auto const it = m_segmentWeights.find(segment); CHECK(it != m_segmentWeights.cend(), ()); @@ -420,7 +420,7 @@ unique_ptr BuildWorldGraph(unique_ptr(); indexLoader->AddGraph(kTestNumMwmId, move(graph)); return make_unique(nullptr /* crossMwmGraph */, move(indexLoader), - estimator, MwmHierarchyHandler(nullptr, nullptr)); + estimator, MwmHierarchyHandler(nullptr, nullptr), nullptr); } unique_ptr BuildIndexGraph(unique_ptr geometryLoader, @@ -442,7 +442,7 @@ unique_ptr BuildWorldGraph(unique_ptr(); indexLoader->AddGraph(kTestNumMwmId, move(graph)); return make_unique(nullptr /* crossMwmGraph */, move(indexLoader), - estimator, MwmHierarchyHandler(nullptr, nullptr)); + estimator, MwmHierarchyHandler(nullptr, nullptr), nullptr); } unique_ptr BuildWorldGraph(unique_ptr geometryLoader, @@ -518,13 +518,13 @@ void TestRouteGeometry(IndexGraphStarter & starter, for (auto const & routeSeg : routeSegs) { - auto const & ll = starter.GetPoint(routeSeg, false /* front */); + auto const & ll = starter.GetPoint(routeSeg, false /* front */, true); // Note. In case of A* router all internal points of route are duplicated. // So it's necessary to exclude the duplicates. pushPoint(ll); } - pushPoint(starter.GetPoint(routeSegs.back(), false /* front */)); + pushPoint(starter.GetPoint(routeSegs.back(), false /* front */, true)); TEST_EQUAL(geom.size(), expectedRouteGeom.size(), ("geom:", geom, "expectedRouteGeom:", expectedRouteGeom)); for (size_t i = 0; i < geom.size(); ++i) { @@ -582,8 +582,8 @@ void TestRestrictions(double expectedLength, double length = 0.0; for (auto const & segment : segments) { - auto const back = mercator::FromLatLon(starter.GetPoint(segment, false /* front */)); - auto const front = mercator::FromLatLon(starter.GetPoint(segment, true /* front */)); + auto const back = mercator::FromLatLon(starter.GetPoint(segment, false /* front */, true)); + auto const front = mercator::FromLatLon(starter.GetPoint(segment, true /* front */, true)); length += back.Length(front); } diff --git a/routing/routing_tests/index_graph_tools.hpp b/routing/routing_tests/index_graph_tools.hpp index adba903d74d..598253579fe 100644 --- a/routing/routing_tests/index_graph_tools.hpp +++ b/routing/routing_tests/index_graph_tools.hpp @@ -55,10 +55,10 @@ class WorldGraphForAStar : public AStarGraph // AStarGraph overrides: // @{ - Weight HeuristicCostEstimate(Vertex const & from, Vertex const & to) override + Weight HeuristicCostEstimate(Vertex const & from, Vertex const & to, bool isOutgoing) override { - return m_graph->HeuristicCostEstimate(m_graph->GetPoint(from, true /* front */), - m_graph->GetPoint(to, true /* front */)); + return m_graph->HeuristicCostEstimate(m_graph->GetPoint(from, true /* front */, isOutgoing), + m_graph->GetPoint(to, true /* front */, isOutgoing), isOutgoing); } void GetOutgoingEdgesList(astar::VertexData const & vertexData, @@ -119,7 +119,7 @@ class ZeroGeometryLoader final : public routing::GeometryLoader // GeometryLoader overrides: ~ZeroGeometryLoader() override = default; - void Load(uint32_t featureId, routing::RoadGeometry & road) override; + void Load(uint32_t featureId, bool isOutgoing, routing::RoadGeometry & road) override; }; class TestIndexGraphLoader final : public IndexGraphLoader @@ -177,7 +177,7 @@ class WeightedEdgeEstimator final : public EdgeEstimator ~WeightedEdgeEstimator() override = default; double CalcSegmentWeight(Segment const & segment, RoadGeometry const & /* road */, - EdgeEstimator::Purpose purpose) const override; + EdgeEstimator::Purpose purpose, bool isOutgoing) const override; double GetUTurnPenalty(Purpose purpose) const override; double GetFerryLandingPenalty(Purpose purpose) const override; diff --git a/routing/routing_tests/routing_algorithm.cpp b/routing/routing_tests/routing_algorithm.cpp index 5f023a6a3c6..e63e009dd97 100644 --- a/routing/routing_tests/routing_algorithm.cpp +++ b/routing/routing_tests/routing_algorithm.cpp @@ -45,7 +45,7 @@ void UndirectedGraph::GetOutgoingEdgesList(astar::VertexData con GetEdgesList(vertexData.m_vertex, true /* isOutgoing */, adj); } -double UndirectedGraph::HeuristicCostEstimate(Vertex const & v, Vertex const & w) +double UndirectedGraph::HeuristicCostEstimate(Vertex const & v, Vertex const & w, bool) { return 0.0; } @@ -157,7 +157,7 @@ class RoadGraph : public Algorithm::Graph } } - double HeuristicCostEstimate(Vertex const & v, Vertex const & w) override + double HeuristicCostEstimate(Vertex const & v, Vertex const & w, bool) override { return TimeBetweenSec(v, w, m_maxSpeedMPS); } @@ -205,7 +205,8 @@ TestAStarBidirectionalAlgo::Result TestAStarBidirectionalAlgo::CalculateRoute( { RoadGraph roadGraph(graph); base::Cancellable cancellable; - Algorithm::Params<> params(roadGraph, startPos, finalPos, {} /* prevRoute */, + CHECK(false, ("roadGraph should be duplicated")); + Algorithm::Params<> params(roadGraph, roadGraph, startPos, finalPos, {} /* prevRoute */, cancellable); Algorithm::Result const res = Algorithm().FindPathBidirectional(params, path); diff --git a/routing/routing_tests/routing_algorithm.hpp b/routing/routing_tests/routing_algorithm.hpp index 9057279e09b..50bd676681f 100644 --- a/routing/routing_tests/routing_algorithm.hpp +++ b/routing/routing_tests/routing_algorithm.hpp @@ -39,7 +39,7 @@ class UndirectedGraph : public AStarGraph std::vector & adj) override; void GetOutgoingEdgesList(astar::VertexData const & vertexData, std::vector & adj) override; - double HeuristicCostEstimate(Vertex const & v, Vertex const & w) override; + double HeuristicCostEstimate(Vertex const & v, Vertex const & w, bool) override; // @} void GetEdgesList(Vertex const & vertex, bool /* isOutgoing */, std::vector & adj); diff --git a/routing/single_vehicle_world_graph.cpp b/routing/single_vehicle_world_graph.cpp index eb40b9fccc5..7e580e7bce1 100644 --- a/routing/single_vehicle_world_graph.cpp +++ b/routing/single_vehicle_world_graph.cpp @@ -22,16 +22,47 @@ SingleVehicleWorldGraph::AStarParents::kEmpty = {}; SingleVehicleWorldGraph::SingleVehicleWorldGraph(unique_ptr crossMwmGraph, unique_ptr loader, shared_ptr estimator, - MwmHierarchyHandler && hierarchyHandler) + MwmHierarchyHandler && hierarchyHandler, + std::shared_ptr numMwmIds) : m_crossMwmGraph(move(crossMwmGraph)) , m_loader(move(loader)) , m_estimator(move(estimator)) , m_hierarchyHandler(std::move(hierarchyHandler)) + , m_numMwmIds(std::move(numMwmIds)) { CHECK(m_loader, ()); CHECK(m_estimator, ()); } +void SingleVehicleWorldGraph::MultithreadingIssue(DataSource & dataSource) +{ + LOG(LINFO, ("SingleVehicleWorldGraph::MultithreadingIssue()")); + platform::CountryFile const & file = m_numMwmIds->GetFile(749 /* Moscow */); + MwmSet::MwmHandle handle = dataSource.GetMwmHandleByCountryFile(file); + if (!handle.IsAlive()) + MYTHROW(RoutingException, ("Can't get mwm handle for", file)); + + auto wave = [&](bool isOutgoing){ + LOG(LINFO, ("SingleVehicleWorldGraph::MultithreadingIssue() --------- wave ---------", isOutgoing)); + FeaturesLoaderGuard guard(dataSource, handle.GetId()); + size_t pointCounts = 0; + for (uint32_t i = 1; i < 600'000; ++i) + { + auto feature = guard.GetFeatureByIndex(i); + if (!feature) + MYTHROW(RoutingException, ("Feature", i, "not found in Moscow.")); + + feature->ParseGeometry(FeatureType::BEST_GEOMETRY); + pointCounts += feature->GetPointsCount(); + } + LOG(LINFO, ("SingleVehicleWorldGraph::MultithreadingIssue() --------- wave end ----", isOutgoing, pointCounts)); + }; + auto backwardWave = std::async(std::launch::async, wave, false /* isOutgoing */); + wave(true /* isOutgoing */); + backwardWave.get(); + LOG(LINFO, ("SingleVehicleWorldGraph::MultithreadingIssue() end.")); +} + void SingleVehicleWorldGraph::CheckAndProcessTransitFeatures(Segment const & parent, vector & jointEdges, vector & parentWeights, @@ -125,39 +156,39 @@ void SingleVehicleWorldGraph::GetEdgeList( } LatLonWithAltitude const & SingleVehicleWorldGraph::GetJunction(Segment const & segment, - bool front) + bool front, bool isOutgoing) { - return GetRoadGeometry(segment.GetMwmId(), segment.GetFeatureId()) + return GetRoadGeometry(segment.GetMwmId(), segment.GetFeatureId(), isOutgoing) .GetJunction(segment.GetPointId(front)); } -ms::LatLon const & SingleVehicleWorldGraph::GetPoint(Segment const & segment, bool front) +ms::LatLon const & SingleVehicleWorldGraph::GetPoint(Segment const & segment, bool front, bool isOutgoing) { - return GetJunction(segment, front).GetLatLon(); + return GetJunction(segment, front, isOutgoing).GetLatLon(); } -bool SingleVehicleWorldGraph::IsOneWay(NumMwmId mwmId, uint32_t featureId) +bool SingleVehicleWorldGraph::IsOneWay(NumMwmId mwmId, uint32_t featureId, bool isOutgoing) { - return GetRoadGeometry(mwmId, featureId).IsOneWay(); + return GetRoadGeometry(mwmId, featureId, isOutgoing).IsOneWay(); } bool SingleVehicleWorldGraph::IsPassThroughAllowed(NumMwmId mwmId, uint32_t featureId) { - return GetRoadGeometry(mwmId, featureId).IsPassThroughAllowed(); + return GetRoadGeometry(mwmId, featureId, true).IsPassThroughAllowed(); /// !!! } RouteWeight SingleVehicleWorldGraph::HeuristicCostEstimate(ms::LatLon const & from, - ms::LatLon const & to) + ms::LatLon const & to, bool isOutgoing) { return RouteWeight(m_estimator->CalcHeuristic(from, to)); } RouteWeight SingleVehicleWorldGraph::CalcSegmentWeight(Segment const & segment, - EdgeEstimator::Purpose purpose) + EdgeEstimator::Purpose purpose, bool isOutgoing) { return RouteWeight(m_estimator->CalcSegmentWeight( - segment, GetRoadGeometry(segment.GetMwmId(), segment.GetFeatureId()), purpose)); + segment, GetRoadGeometry(segment.GetMwmId(), segment.GetFeatureId(), isOutgoing), purpose, isOutgoing)); } RouteWeight SingleVehicleWorldGraph::CalcLeapWeight(ms::LatLon const & from, @@ -185,8 +216,8 @@ double SingleVehicleWorldGraph::CalculateETA(Segment const & from, Segment const double SingleVehicleWorldGraph::CalculateETAWithoutPenalty(Segment const & segment) { return m_estimator->CalcSegmentWeight(segment, - GetRoadGeometry(segment.GetMwmId(), segment.GetFeatureId()), - EdgeEstimator::Purpose::ETA); + GetRoadGeometry(segment.GetMwmId(), segment.GetFeatureId(), true), + EdgeEstimator::Purpose::ETA, true); } vector const & SingleVehicleWorldGraph::GetTransitions(NumMwmId numMwmId, bool isEnter) @@ -202,9 +233,9 @@ vector SingleVehicleWorldGraph::GetSpeedCamInfo(Segme return m_loader->GetSpeedCameraInfo(segment); } -RoadGeometry const & SingleVehicleWorldGraph::GetRoadGeometry(NumMwmId mwmId, uint32_t featureId) +RoadGeometry const & SingleVehicleWorldGraph::GetRoadGeometry(NumMwmId mwmId, uint32_t featureId, bool isOutgoing) { - return m_loader->GetGeometry(mwmId).GetRoad(featureId); + return m_loader->GetGeometry(mwmId).GetRoad(featureId, isOutgoing); } void SingleVehicleWorldGraph::GetTwinsInner(Segment const & segment, bool isOutgoing, @@ -213,17 +244,17 @@ void SingleVehicleWorldGraph::GetTwinsInner(Segment const & segment, bool isOutg m_crossMwmGraph->GetTwins(segment, isOutgoing, twins); } -bool SingleVehicleWorldGraph::IsRoutingOptionsGood(Segment const & segment) +bool SingleVehicleWorldGraph::IsRoutingOptionsGood(Segment const & segment, bool isOutgoing) { - auto const & geometry = GetRoadGeometry(segment.GetMwmId(), segment.GetFeatureId()); + auto const & geometry = GetRoadGeometry(segment.GetMwmId(), segment.GetFeatureId(), isOutgoing); return geometry.SuitableForOptions(m_avoidRoutingOptions); } -RoutingOptions SingleVehicleWorldGraph::GetRoutingOptions(Segment const & segment) +RoutingOptions SingleVehicleWorldGraph::GetRoutingOptions(Segment const & segment, bool isOutgoing) { ASSERT(segment.IsRealSegment(), ()); - auto const & geometry = GetRoadGeometry(segment.GetMwmId(), segment.GetFeatureId()); + auto const & geometry = GetRoadGeometry(segment.GetMwmId(), segment.GetFeatureId(), isOutgoing); return geometry.GetRoutingOptions(); } diff --git a/routing/single_vehicle_world_graph.hpp b/routing/single_vehicle_world_graph.hpp index 2b4fad49ed1..6546c3f739d 100644 --- a/routing/single_vehicle_world_graph.hpp +++ b/routing/single_vehicle_world_graph.hpp @@ -31,7 +31,9 @@ class SingleVehicleWorldGraph final : public WorldGraph SingleVehicleWorldGraph(std::unique_ptr crossMwmGraph, std::unique_ptr loader, std::shared_ptr estimator, - MwmHierarchyHandler && hierarchyHandler); + MwmHierarchyHandler && hierarchyHandler, std::shared_ptr numMwmIds); + + void MultithreadingIssue(DataSource & dataSource) override; // WorldGraph overrides: // @{ @@ -50,19 +52,19 @@ class SingleVehicleWorldGraph final : public WorldGraph bool CheckLength(RouteWeight const &, double) const override { return true; } - LatLonWithAltitude const & GetJunction(Segment const & segment, bool front) override; - ms::LatLon const & GetPoint(Segment const & segment, bool front) override; + LatLonWithAltitude const & GetJunction(Segment const & segment, bool front, bool isOutgoing) override; + ms::LatLon const & GetPoint(Segment const & segment, bool front, bool isOutgoing) override; - bool IsOneWay(NumMwmId mwmId, uint32_t featureId) override; + bool IsOneWay(NumMwmId mwmId, uint32_t featureId, bool isOutgoing) override; bool IsPassThroughAllowed(NumMwmId mwmId, uint32_t featureId) override; void ClearCachedGraphs() override { m_loader->Clear(); } void SetMode(WorldGraphMode mode) override { m_mode = mode; } WorldGraphMode GetMode() const override { return m_mode; } - RouteWeight HeuristicCostEstimate(ms::LatLon const & from, ms::LatLon const & to) override; + RouteWeight HeuristicCostEstimate(ms::LatLon const & from, ms::LatLon const & to, bool isOutgoing) override; - RouteWeight CalcSegmentWeight(Segment const & segment, EdgeEstimator::Purpose purpose) override; + RouteWeight CalcSegmentWeight(Segment const & segment, EdgeEstimator::Purpose purpose, bool isOutgoing) override; RouteWeight CalcLeapWeight(ms::LatLon const & from, ms::LatLon const & to) const override; RouteWeight CalcOffroadWeight(ms::LatLon const & from, ms::LatLon const & to, EdgeEstimator::Purpose purpose) const override; @@ -73,8 +75,8 @@ class SingleVehicleWorldGraph final : public WorldGraph void SetRoutingOptions(RoutingOptions routingOptions) override { m_avoidRoutingOptions = routingOptions; } /// \returns true if feature, associated with segment satisfies users conditions. - bool IsRoutingOptionsGood(Segment const & segment) override; - RoutingOptions GetRoutingOptions(Segment const & segment) override; + bool IsRoutingOptionsGood(Segment const & segment, bool isOutgoing) override; + RoutingOptions GetRoutingOptions(Segment const & segment, bool isOutgoing) override; std::unique_ptr GetTransitInfo(Segment const & segment) override; std::vector GetSpeedCamInfo(Segment const & segment) override; @@ -124,7 +126,7 @@ class SingleVehicleWorldGraph final : public WorldGraph // WorldGraph overrides: void GetTwinsInner(Segment const & s, bool isOutgoing, std::vector & twins) override; - RoadGeometry const & GetRoadGeometry(NumMwmId mwmId, uint32_t featureId); + RoadGeometry const & GetRoadGeometry(NumMwmId mwmId, uint32_t featureId, bool isOutgoing); std::unique_ptr m_crossMwmGraph; std::unique_ptr m_loader; @@ -145,5 +147,6 @@ class SingleVehicleWorldGraph final : public WorldGraph AStarParents m_parentsForJoints; MwmHierarchyHandler m_hierarchyHandler; + std::shared_ptr m_numMwmIds; }; } // namespace routing diff --git a/routing/transit_graph.cpp b/routing/transit_graph.cpp index 9da2a00b0b5..2d7226b5ecc 100644 --- a/routing/transit_graph.cpp +++ b/routing/transit_graph.cpp @@ -60,7 +60,7 @@ LatLonWithAltitude const & TransitGraph::GetJunction(Segment const & segment, } RouteWeight TransitGraph::CalcSegmentWeight(Segment const & segment, - EdgeEstimator::Purpose purpose) const + EdgeEstimator::Purpose purpose, bool isOutgoing) const { CHECK(IsTransitSegment(segment), ("Nontransit segment passed to TransitGraph.")); @@ -187,7 +187,7 @@ void TransitGraph::GetTransitEdges(Segment const & segment, bool isOutgoing, auto const & from = isOutgoing ? segment : s; auto const & to = isOutgoing ? s : segment; edges.emplace_back( - s, CalcSegmentWeight(to, EdgeEstimator::Purpose::Weight) + GetTransferPenalty(from, to)); + s, CalcSegmentWeight(to, EdgeEstimator::Purpose::Weight, isOutgoing) + GetTransferPenalty(from, to)); } } diff --git a/routing/transit_graph.hpp b/routing/transit_graph.hpp index 01ec75ea59a..7cdf6af81a5 100644 --- a/routing/transit_graph.hpp +++ b/routing/transit_graph.hpp @@ -43,7 +43,7 @@ class TransitGraph final ::transit::TransitVersion GetTransitVersion() const; LatLonWithAltitude const & GetJunction(Segment const & segment, bool front) const; - RouteWeight CalcSegmentWeight(Segment const & segment, EdgeEstimator::Purpose purpose) const; + RouteWeight CalcSegmentWeight(Segment const & segment, EdgeEstimator::Purpose purpose, bool isOutgoing) const; RouteWeight GetTransferPenalty(Segment const & from, Segment const & to) const; void GetTransitEdges(Segment const & segment, bool isOutgoing, std::vector & edges) const; diff --git a/routing/transit_world_graph.cpp b/routing/transit_world_graph.cpp index 4f54f1fa018..d9c3fb912cf 100644 --- a/routing/transit_world_graph.cpp +++ b/routing/transit_world_graph.cpp @@ -38,8 +38,8 @@ void TransitWorldGraph::GetEdgeList(astar::VertexData cons Segment real; if (transitGraph.FindReal(segment, real)) { - bool const haveSameFront = GetJunction(segment, true /* front */) == GetJunction(real, true); - bool const haveSameBack = GetJunction(segment, false /* front */) == GetJunction(real, false); + bool const haveSameFront = GetJunction(segment, true /* front */, isOutgoing) == GetJunction(real, true, isOutgoing); + bool const haveSameBack = GetJunction(segment, false /* front */, isOutgoing) == GetJunction(real, false, isOutgoing); if ((isOutgoing && haveSameFront) || (!isOutgoing && haveSameBack)) { astar::VertexData const data(real, vertexData.m_realDistance); @@ -60,8 +60,8 @@ void TransitWorldGraph::GetEdgeList(astar::VertexData cons auto const & edgeSegment = edge.GetTarget(); for (auto const & s : transitGraph.GetFake(edgeSegment)) { - bool const haveSameFront = GetJunction(edgeSegment, true /* front */) == GetJunction(s, true); - bool const haveSameBack = GetJunction(edgeSegment, false /* front */) == GetJunction(s, false); + bool const haveSameFront = GetJunction(edgeSegment, true /* front */, isOutgoing) == GetJunction(s, true, isOutgoing); + bool const haveSameBack = GetJunction(edgeSegment, false /* front */, isOutgoing) == GetJunction(s, false, isOutgoing); if ((isOutgoing && haveSameBack) || (!isOutgoing && haveSameFront)) fakeFromReal.emplace_back(s, edge.GetWeight()); } @@ -77,7 +77,7 @@ void TransitWorldGraph::GetEdgeList( CHECK(false, ("TransitWorldGraph does not support Joints mode.")); } -LatLonWithAltitude const & TransitWorldGraph::GetJunction(Segment const & segment, bool front) +LatLonWithAltitude const & TransitWorldGraph::GetJunction(Segment const & segment, bool front, bool isOutgoing) { if (TransitGraph::IsTransitSegment(segment)) return GetTransitGraph(segment.GetMwmId()).GetJunction(segment, front); @@ -86,12 +86,12 @@ LatLonWithAltitude const & TransitWorldGraph::GetJunction(Segment const & segmen .GetJunction(segment.GetPointId(front)); } -ms::LatLon const & TransitWorldGraph::GetPoint(Segment const & segment, bool front) +ms::LatLon const & TransitWorldGraph::GetPoint(Segment const & segment, bool front, bool isOutgoing) { - return GetJunction(segment, front).GetLatLon(); + return GetJunction(segment, front, isOutgoing).GetLatLon(); } -bool TransitWorldGraph::IsOneWay(NumMwmId mwmId, uint32_t featureId) +bool TransitWorldGraph::IsOneWay(NumMwmId mwmId, uint32_t featureId, bool isOutgoing) { if (TransitGraph::IsTransitFeature(featureId)) return true; @@ -111,22 +111,22 @@ void TransitWorldGraph::ClearCachedGraphs() m_transitLoader->Clear(); } -RouteWeight TransitWorldGraph::HeuristicCostEstimate(ms::LatLon const & from, ms::LatLon const & to) +RouteWeight TransitWorldGraph::HeuristicCostEstimate(ms::LatLon const & from, ms::LatLon const & to, bool isOutgoing) { return RouteWeight(m_estimator->CalcHeuristic(from, to)); } RouteWeight TransitWorldGraph::CalcSegmentWeight(Segment const & segment, - EdgeEstimator::Purpose purpose) + EdgeEstimator::Purpose purpose, bool isOutgoing) { if (TransitGraph::IsTransitSegment(segment)) { TransitGraph & transitGraph = GetTransitGraph(segment.GetMwmId()); - return transitGraph.CalcSegmentWeight(segment, purpose); + return transitGraph.CalcSegmentWeight(segment, purpose, isOutgoing); } return RouteWeight(m_estimator->CalcSegmentWeight( - segment, GetRealRoadGeometry(segment.GetMwmId(), segment.GetFeatureId()), purpose)); + segment, GetRealRoadGeometry(segment.GetMwmId(), segment.GetFeatureId()), purpose, isOutgoing)); } RouteWeight TransitWorldGraph::CalcLeapWeight(ms::LatLon const & from, ms::LatLon const & to) const @@ -144,15 +144,15 @@ RouteWeight TransitWorldGraph::CalcOffroadWeight(ms::LatLon const & from, double TransitWorldGraph::CalculateETA(Segment const & from, Segment const & to) { if (TransitGraph::IsTransitSegment(from)) - return CalcSegmentWeight(to, EdgeEstimator::Purpose::ETA).GetWeight(); + return CalcSegmentWeight(to, EdgeEstimator::Purpose::ETA, true).GetWeight(); if (TransitGraph::IsTransitSegment(to)) - return CalcSegmentWeight(to, EdgeEstimator::Purpose::ETA).GetWeight(); + return CalcSegmentWeight(to, EdgeEstimator::Purpose::ETA, true).GetWeight(); if (from.GetMwmId() != to.GetMwmId()) { return m_estimator->CalcSegmentWeight(to, GetRealRoadGeometry(to.GetMwmId(), to - .GetFeatureId()), EdgeEstimator::Purpose::ETA); + .GetFeatureId()), EdgeEstimator::Purpose::ETA, true); } auto & indexGraph = m_indexLoader->GetIndexGraph(from.GetMwmId()); @@ -164,11 +164,11 @@ double TransitWorldGraph::CalculateETA(Segment const & from, Segment const & to) double TransitWorldGraph::CalculateETAWithoutPenalty(Segment const & segment) { if (TransitGraph::IsTransitSegment(segment)) - return CalcSegmentWeight(segment, EdgeEstimator::Purpose::ETA).GetWeight(); + return CalcSegmentWeight(segment, EdgeEstimator::Purpose::ETA, true).GetWeight(); return m_estimator->CalcSegmentWeight( segment, GetRealRoadGeometry(segment.GetMwmId(), segment.GetFeatureId()), - EdgeEstimator::Purpose::ETA); + EdgeEstimator::Purpose::ETA, true); } unique_ptr TransitWorldGraph::GetTransitInfo(Segment const & segment) @@ -217,7 +217,7 @@ void TransitWorldGraph::GetTwinsInner(Segment const & segment, bool isOutgoing, RoadGeometry const & TransitWorldGraph::GetRealRoadGeometry(NumMwmId mwmId, uint32_t featureId) { CHECK(!TransitGraph::IsTransitFeature(featureId), ("GetRealRoadGeometry not designed for transit.")); - return m_indexLoader->GetGeometry(mwmId).GetRoad(featureId); + return m_indexLoader->GetGeometry(mwmId).GetRoad(featureId, true /* isOutgoing */); } void TransitWorldGraph::AddRealEdges(astar::VertexData const & vertexData, diff --git a/routing/transit_world_graph.hpp b/routing/transit_world_graph.hpp index fd7d1dd9824..1743e815840 100644 --- a/routing/transit_world_graph.hpp +++ b/routing/transit_world_graph.hpp @@ -51,19 +51,19 @@ class TransitWorldGraph final : public WorldGraph return weight.GetWeight() - weight.GetTransitTime() <= MaxPedestrianTimeSec(startToFinishDistanceM); } - LatLonWithAltitude const & GetJunction(Segment const & segment, bool front) override; - ms::LatLon const & GetPoint(Segment const & segment, bool front) override; + LatLonWithAltitude const & GetJunction(Segment const & segment, bool front, bool isOutgoing) override; + ms::LatLon const & GetPoint(Segment const & segment, bool front, bool isOutgoing) override; // All transit features are oneway. - bool IsOneWay(NumMwmId mwmId, uint32_t featureId) override; + bool IsOneWay(NumMwmId mwmId, uint32_t featureId, bool isOutgoing) override; // All transit features are allowed for through passage. bool IsPassThroughAllowed(NumMwmId mwmId, uint32_t featureId) override; void ClearCachedGraphs() override; void SetMode(WorldGraphMode mode) override { m_mode = mode; } WorldGraphMode GetMode() const override { return m_mode; } - RouteWeight HeuristicCostEstimate(ms::LatLon const & from, ms::LatLon const & to) override; + RouteWeight HeuristicCostEstimate(ms::LatLon const & from, ms::LatLon const & to, bool isOutgoing) override; - RouteWeight CalcSegmentWeight(Segment const & segment, EdgeEstimator::Purpose purpose) override; + RouteWeight CalcSegmentWeight(Segment const & segment, EdgeEstimator::Purpose purpose, bool isOutgoing) override; RouteWeight CalcLeapWeight(ms::LatLon const & from, ms::LatLon const & to) const override; RouteWeight CalcOffroadWeight(ms::LatLon const & from, ms::LatLon const & to, EdgeEstimator::Purpose purpose) const override; diff --git a/routing/world_graph.cpp b/routing/world_graph.cpp index 9bb48ec7131..b2954f1c004 100644 --- a/routing/world_graph.cpp +++ b/routing/world_graph.cpp @@ -28,12 +28,12 @@ void WorldGraph::GetTwins(Segment const & segment, bool isOutgoing, bool useRout SetMode(prevMode); } -RoutingOptions WorldGraph::GetRoutingOptions(Segment const & /* segment */) +RoutingOptions WorldGraph::GetRoutingOptions(Segment const & /* segment */, bool isOutgoing) { return {}; } -bool WorldGraph::IsRoutingOptionsGood(Segment const & /* segment */) +bool WorldGraph::IsRoutingOptionsGood(Segment const & /* segment */, bool isOutgoing) { return true; } diff --git a/routing/world_graph.hpp b/routing/world_graph.hpp index ed1f827efb0..32861282f96 100644 --- a/routing/world_graph.hpp +++ b/routing/world_graph.hpp @@ -50,6 +50,8 @@ class WorldGraph virtual ~WorldGraph() = default; + virtual void MultithreadingIssue(DataSource & dataSource) {} + virtual void GetEdgeList(astar::VertexData const & vertexData, bool isOutgoing, bool useRoutingOptions, bool useAccessConditional, std::vector & edges) = 0; @@ -65,9 +67,9 @@ class WorldGraph // start to finish of the route. virtual bool CheckLength(RouteWeight const & weight, double startToFinishDistanceM) const = 0; - virtual LatLonWithAltitude const & GetJunction(Segment const & segment, bool front) = 0; - virtual ms::LatLon const & GetPoint(Segment const & segment, bool front) = 0; - virtual bool IsOneWay(NumMwmId mwmId, uint32_t featureId) = 0; + virtual LatLonWithAltitude const & GetJunction(Segment const & segment, bool front, bool isOutgoing) = 0; + virtual ms::LatLon const & GetPoint(Segment const & segment, bool front, bool isOutgoing) = 0; + virtual bool IsOneWay(NumMwmId mwmId, uint32_t featureId, bool isOutgoing) = 0; // Checks whether feature is allowed for through passage. virtual bool IsPassThroughAllowed(NumMwmId mwmId, uint32_t featureId) = 0; @@ -77,10 +79,10 @@ class WorldGraph virtual void SetMode(WorldGraphMode mode) = 0; virtual WorldGraphMode GetMode() const = 0; - virtual RouteWeight HeuristicCostEstimate(ms::LatLon const & from, ms::LatLon const & to) = 0; + virtual RouteWeight HeuristicCostEstimate(ms::LatLon const & from, ms::LatLon const & to, bool isOutgoing) = 0; virtual RouteWeight CalcSegmentWeight(Segment const & segment, - EdgeEstimator::Purpose purpose) = 0; + EdgeEstimator::Purpose purpose, bool isOutgoin) = 0; virtual RouteWeight CalcLeapWeight(ms::LatLon const & from, ms::LatLon const & to) const = 0; @@ -93,8 +95,8 @@ class WorldGraph /// \returns transitions for mwm with id |numMwmId|. virtual std::vector const & GetTransitions(NumMwmId numMwmId, bool isEnter); - virtual bool IsRoutingOptionsGood(Segment const & /* segment */); - virtual RoutingOptions GetRoutingOptions(Segment const & /* segment */); + virtual bool IsRoutingOptionsGood(Segment const & /* segment */, bool isOutgoing); + virtual RoutingOptions GetRoutingOptions(Segment const & /* segment */, bool isOutgoing); virtual void SetRoutingOptions(RoutingOptions /* routingOptions */); virtual void SetAStarParents(bool forward, Parents & parents); diff --git a/track_analyzing/track_analyzer/cmd_tracks.cpp b/track_analyzing/track_analyzer/cmd_tracks.cpp index d06e9ce7db4..3e68afe6f8b 100644 --- a/track_analyzing/track_analyzer/cmd_tracks.cpp +++ b/track_analyzing/track_analyzer/cmd_tracks.cpp @@ -115,8 +115,8 @@ double EstimateDuration(MatchedTrack const & track, shared_ptr es continue; segment = point.GetSegment(); - result += estimator->CalcSegmentWeight(segment, geometry.GetRoad(segment.GetFeatureId()), - EdgeEstimator::Purpose::ETA); + result += estimator->CalcSegmentWeight(segment, geometry.GetRoad(segment.GetFeatureId(), true /* isOutgoing */), + EdgeEstimator::Purpose::ETA, true); } return result; diff --git a/track_analyzing/track_analyzer/crossroad_checker.cpp b/track_analyzing/track_analyzer/crossroad_checker.cpp index 3aa17c7d5fe..a5e502117f7 100644 --- a/track_analyzing/track_analyzer/crossroad_checker.cpp +++ b/track_analyzing/track_analyzer/crossroad_checker.cpp @@ -78,9 +78,9 @@ namespace routing IsCrossroadChecker::Type IsCrossroadChecker::operator()(Segment const & current, Segment const & next) const { auto const currentSegmentFeatureId = current.GetFeatureId(); - auto const currentSegmentHwType = m_geometry.GetRoad(currentSegmentFeatureId).GetHighwayType(); + auto const currentSegmentHwType = m_geometry.GetRoad(currentSegmentFeatureId, true /* isOutgoing */).GetHighwayType(); auto const nextSegmentFeatureId = next.GetFeatureId(); - auto const nextSegmentHwType = m_geometry.GetRoad(nextSegmentFeatureId).GetHighwayType(); + auto const nextSegmentHwType = m_geometry.GetRoad(nextSegmentFeatureId, true /* isOutgoing */).GetHighwayType(); auto const currentRoadPoint = current.GetRoadPoint(true /* isFront */); auto const jointId = m_indexGraph.GetJointId(currentRoadPoint); if (jointId == Joint::kInvalidId) @@ -121,7 +121,7 @@ IsCrossroadChecker::Type IsCrossroadChecker::operator()(Segment const & current, if (pointFeatureId == currentSegmentFeatureId || pointFeatureId == nextSegmentFeatureId) return; - auto const & roadGeometry = m_geometry.GetRoad(pointFeatureId); + auto const & roadGeometry = m_geometry.GetRoad(pointFeatureId, true /* isOutgoing */); auto const pointHwType = roadGeometry.GetHighwayType(); if (currentSegmentHwType == pointHwType) return; diff --git a/track_analyzing/track_matcher.cpp b/track_analyzing/track_matcher.cpp index ef21b6dbd84..dbc457c9c18 100644 --- a/track_analyzing/track_matcher.cpp +++ b/track_analyzing/track_matcher.cpp @@ -35,8 +35,8 @@ double DistanceToSegment(m2::PointD const & segmentBegin, m2::PointD const & seg double DistanceToSegment(Segment const & segment, m2::PointD const & point, IndexGraph & indexGraph) { return DistanceToSegment( - mercator::FromLatLon(indexGraph.GetGeometry().GetPoint(segment.GetRoadPoint(false))), - mercator::FromLatLon(indexGraph.GetGeometry().GetPoint(segment.GetRoadPoint(true))), point); + mercator::FromLatLon(indexGraph.GetGeometry().GetPoint(segment.GetRoadPoint(false), true /* isOutgoing */)), + mercator::FromLatLon(indexGraph.GetGeometry().GetPoint(segment.GetRoadPoint(true), true /* isOutgoing */)), point); } bool EdgesContain(vector const & edges, Segment const & segment) diff --git a/track_analyzing/utils.cpp b/track_analyzing/utils.cpp index cb927731cf0..307e50dd0e9 100644 --- a/track_analyzing/utils.cpp +++ b/track_analyzing/utils.cpp @@ -31,8 +31,8 @@ double CalcSubtrackLength(MatchedTrack::const_iterator begin, MatchedTrack::cons { length += ms::DistanceOnEarth( - geometry.GetPoint(segment.GetRoadPoint(false /* front */)), - geometry.GetPoint(segment.GetRoadPoint(true /* front */))); + geometry.GetPoint(segment.GetRoadPoint(false /* front */), true /* isOutgoing */), + geometry.GetPoint(segment.GetRoadPoint(true /* front */), true /* isOutgoing */)); prevSegment = segment; } }