diff --git a/include/engine/api/table_parameters.hpp b/include/engine/api/table_parameters.hpp index 0f3d0b4b1..395e506f3 100644 --- a/include/engine/api/table_parameters.hpp +++ b/include/engine/api/table_parameters.hpp @@ -36,7 +36,7 @@ struct TableParameters : public BaseParameters return false; // 3/ 0 <= index < len(locations) - const auto is_not_in_range = [](const std::size_t x) + const auto not_in_range = [this](const std::size_t x) { return x >= coordinates.size(); }; diff --git a/include/engine/engine.hpp b/include/engine/engine.hpp index ee75c5b69..5449dc94a 100644 --- a/include/engine/engine.hpp +++ b/include/engine/engine.hpp @@ -26,10 +26,12 @@ struct EngineConfig; namespace api { struct RouteParameters; +struct TableParameters; } namespace plugins { class ViaRoutePlugin; +class DistanceTablePlugin; } namespace datafacade { @@ -39,26 +41,20 @@ class BaseDataFacade; class Engine final { public: - struct EngineLock - { - // will only be initialized if shared memory is used - storage::SharedBarriers barrier; - // decrease number of concurrent queries - void DecreaseQueryCount(); - // increase number of concurrent queries - void IncreaseQueryCount(); - }; - - Engine(EngineConfig &config_); - + Engine(EngineConfig &config); Engine(const Engine &) = delete; Engine &operator=(const Engine &) = delete; - Status Route(const api::RouteParameters &route_parameters, util::json::Object &json_result); + Status Route(const api::RouteParameters ¶meters, util::json::Object &result); + Status Table(const api::TableParameters ¶meters, util::json::Object &result); private: + struct EngineLock; std::unique_ptr lock; + std::unique_ptr route_plugin; + std::unique_ptr table_plugin; + std::unique_ptr query_data_facade; }; } diff --git a/include/engine/plugins/distance_table.hpp b/include/engine/plugins/distance_table.hpp index 9f6287ac3..997e1616f 100644 --- a/include/engine/plugins/distance_table.hpp +++ b/include/engine/plugins/distance_table.hpp @@ -3,8 +3,10 @@ #include "engine/plugins/plugin_base.hpp" +#include "engine/api/table_parameters.hpp" #include "engine/object_encoder.hpp" -#include "engine/search_engine.hpp" +#include "engine/routing_algorithms/many_to_many.hpp" +#include "engine/search_engine_data.hpp" #include "util/make_unique.hpp" #include "util/string_util.hpp" #include "osrm/json_container.hpp" @@ -23,109 +25,57 @@ namespace engine namespace plugins { -template class DistanceTablePlugin final : public BasePlugin +class DistanceTablePlugin final : public BasePlugin { private: - std::unique_ptr> search_engine_ptr; + SearchEngineData heaps; + routing_algorithms::ManyToManyRouting distance_table; int max_locations_distance_table; public: - explicit DistanceTablePlugin(DataFacadeT *facade, const int max_locations_distance_table) - : max_locations_distance_table(max_locations_distance_table), descriptor_string("table"), - facade(facade) + explicit DistanceTablePlugin(datafacade::BaseDataFacade *facade, + const int max_locations_distance_table) + : BasePlugin{*facade}, distance_table(facade, heaps), + max_locations_distance_table(max_locations_distance_table) { - search_engine_ptr = util::make_unique>(facade); } - virtual ~DistanceTablePlugin() {} - - const std::string GetDescriptor() const override final { return descriptor_string; } - - Status HandleRequest(const RouteParameters &route_parameters, - util::json::Object &json_result) override final + Status HandleRequest(const api::TableParameters ¶ms, util::json::Object &result) { - return NonConstHandleRequest(route_parameters, json_result); - } + BOOST_ASSERT(params.IsValid()); - // XXX: should be const-ref, but we need to artificially source, destination values - // so consider this a hack for 4.9, in 5.0 we refactored and handle it beautifully! - Status NonConstHandleRequest(RouteParameters route_parameters, util::json::Object &json_result) - { - if (!check_all_coordinates(route_parameters.coordinates)) - { - json_result.values["status_message"] = "Coordinates are invalid"; - return Status::Error; - } + if (!CheckAllCoordinates(params.coordinates)) + return Error("invalid-options", "Coordinates are invalid", result); - const auto &input_bearings = route_parameters.bearings; - if (input_bearings.size() > 0 && - route_parameters.coordinates.size() != input_bearings.size()) - { - json_result.values["status_message"] = - "Number of bearings does not match number of coordinates"; - return Status::Error; - } - - const auto number_of_coordinates = route_parameters.coordinates.size(); - - BOOST_ASSERT(route_parameters.is_source.size() <= number_of_coordinates); - BOOST_ASSERT(route_parameters.is_destination.size() <= number_of_coordinates); - - // The check_all_coordinates guard above makes sure we have at least 2 coordinates. - // This establishes the parallel array invariant for is_source, is_destination, coordinates - if (route_parameters.is_source.size() == 0) - { - const auto where = route_parameters.is_source.end(); - const auto n = number_of_coordinates - route_parameters.is_source.size(); - route_parameters.is_source.insert(where, n, true); - } - - if (route_parameters.is_destination.size() == 0) - { - const auto where = route_parameters.is_destination.end(); - const auto n = number_of_coordinates - route_parameters.is_destination.size(); - route_parameters.is_destination.insert(where, n, true); - } - - // parallel array invariant - BOOST_ASSERT(route_parameters.coordinates.size() == route_parameters.is_source.size()); - BOOST_ASSERT(route_parameters.coordinates.size() == route_parameters.is_destination.size()); - - const auto number_of_sources = std::count(route_parameters.is_source.begin(), // - route_parameters.is_source.end(), true); - const auto number_of_destination = std::count(route_parameters.is_destination.begin(), // - route_parameters.is_destination.end(), true); + if (params.bearings.size() > 0 && params.coordinates.size() != params.bearings.size()) + return Error("invalid-options", "Number of bearings does not match number of coordinates", result); if (max_locations_distance_table > 0 && - (number_of_sources * number_of_destination > + (params.sources.size() * params.destinations.size() > max_locations_distance_table * max_locations_distance_table)) - { - json_result.values["status_message"] = - "Number of entries " + std::to_string(number_of_sources * number_of_destination) + + return Error("invalid-options", "Number of entries " + std::to_string(params.sources.size() * params.destinations.size()) + " is higher than current maximum (" + - std::to_string(max_locations_distance_table * max_locations_distance_table) + ")"; - return Status::Error; - } + std::to_string(max_locations_distance_table * max_locations_distance_table) + ")", result); - const bool checksum_OK = (route_parameters.check_sum == facade->GetCheckSum()); + const bool checksum_OK = (params.check_sum == BasePlugin::facade.GetCheckSum()); - std::vector phantom_node_source_vector(number_of_sources); - std::vector phantom_node_target_vector(number_of_destination); + std::vector phantom_node_source_vector(params.sources.size()); + std::vector phantom_node_target_vector(params.destinations.size()); auto phantom_node_source_out_iter = phantom_node_source_vector.begin(); auto phantom_node_target_out_iter = phantom_node_target_vector.begin(); - for (const auto i : util::irange(0u, route_parameters.coordinates.size())) + for (const auto i : util::irange(0u, params.coordinates.size())) { - if (checksum_OK && i < route_parameters.hints.size() && - !route_parameters.hints[i].empty()) + if (checksum_OK && i < params.hints.size() && !params.hints[i].empty()) { - auto current_phantom_node = decodeBase64(route_parameters.hints[i]); - if (current_phantom_node.IsValid(facade->GetNumberOfNodes())) + PhantomNode current_phantom_node; + ObjectEncoder::DecodeFromBase64(params.hints[i], current_phantom_node); + if (current_phantom_node.IsValid(BasePlugin::facade.GetNumberOfNodes())) { - if (route_parameters.is_source[i]) + if (params.is_source[i]) { *phantom_node_source_out_iter = std::make_pair(current_phantom_node, current_phantom_node); - if (route_parameters.is_destination[i]) + if (params.is_destination[i]) { *phantom_node_target_out_iter = *phantom_node_source_out_iter; phantom_node_target_out_iter++; @@ -134,8 +84,7 @@ template class DistanceTablePlugin final : public BasePlugin } else { - BOOST_ASSERT(route_parameters.is_destination[i] && - !route_parameters.is_source[i]); + BOOST_ASSERT(params.is_destination[i] && !params.is_source[i]); *phantom_node_target_out_iter = std::make_pair(current_phantom_node, current_phantom_node); phantom_node_target_out_iter++; @@ -143,26 +92,26 @@ template class DistanceTablePlugin final : public BasePlugin continue; } } - const int bearing = input_bearings.size() > 0 ? input_bearings[i].first : 0; - const int range = input_bearings.size() > 0 - ? (input_bearings[i].second ? *input_bearings[i].second : 10) + const int bearing = params.bearings.size() > 0 ? params.bearings[i].first : 0; + const int range = params.bearings.size() > 0 + ? (params.bearings[i].second ? *param_bearings[i].second : 10) : 180; - - if (route_parameters.is_source[i]) + if (params.is_source[i]) { *phantom_node_source_out_iter = - facade->NearestPhantomNodeWithAlternativeFromBigComponent( - route_parameters.coordinates[i], bearing, range); + BasePlugin::facade.NearestPhantomNodeWithAlternativeFromBigComponent( + params.coordinates[i], bearing, range); // we didn't found a fitting node, return error - if (!phantom_node_source_out_iter->first.IsValid(facade->GetNumberOfNodes())) + if (!phantom_node_source_out_iter->first.IsValid( + BasePlugin::facade.GetNumberOfNodes())) { - json_result.values["status_message"] = + result.values["status_message"] = std::string("Could not find a matching segment for coordinate ") + std::to_string(i); return Status::NoSegment; } - if (route_parameters.is_destination[i]) + if (params.is_destination[i]) { *phantom_node_target_out_iter = *phantom_node_source_out_iter; phantom_node_target_out_iter++; @@ -171,15 +120,16 @@ template class DistanceTablePlugin final : public BasePlugin } else { - BOOST_ASSERT(route_parameters.is_destination[i] && !route_parameters.is_source[i]); + BOOST_ASSERT(params.is_destination[i] && !params.is_source[i]); *phantom_node_target_out_iter = - facade->NearestPhantomNodeWithAlternativeFromBigComponent( - route_parameters.coordinates[i], bearing, range); + BasePlugin::facade.NearestPhantomNodeWithAlternativeFromBigComponent( + params.coordinates[i], bearing, range); // we didn't found a fitting node, return error - if (!phantom_node_target_out_iter->first.IsValid(facade->GetNumberOfNodes())) + if (!phantom_node_target_out_iter->first.IsValid( + BasePlugin::facade.GetNumberOfNodes())) { - json_result.values["status_message"] = + result.values["status_message"] = std::string("Could not find a matching segment for coordinate ") + std::to_string(i); return Status::NoSegment; @@ -189,34 +139,34 @@ template class DistanceTablePlugin final : public BasePlugin } BOOST_ASSERT((phantom_node_source_out_iter - phantom_node_source_vector.begin()) == - number_of_sources); + params.sources.size()); BOOST_ASSERT((phantom_node_target_out_iter - phantom_node_target_vector.begin()) == - number_of_destination); + params.destinations.size()); // FIXME we should clear phantom_node_source_vector and phantom_node_target_vector after // this auto snapped_source_phantoms = snapPhantomNodes(phantom_node_source_vector); auto snapped_target_phantoms = snapPhantomNodes(phantom_node_target_vector); - auto result_table = - search_engine_ptr->distance_table(snapped_source_phantoms, snapped_target_phantoms); + auto result_table = distance_table(snapped_source_phantoms, snapped_target_phantoms); if (!result_table) { - json_result.values["status_message"] = "No distance table found"; + result.values["status_message"] = "No distance table found"; return Status::EmptyResult; } util::json::Array matrix_json_array; - for (const auto row : util::irange(0, number_of_sources)) + for (const auto row : util::irange(0, params.sources.size())) { util::json::Array json_row; - auto row_begin_iterator = result_table->begin() + (row * number_of_destination); - auto row_end_iterator = result_table->begin() + ((row + 1) * number_of_destination); + auto row_begin_iterator = result_table->begin() + (row * params.destinations.size()); + auto row_end_iterator = + result_table->begin() + ((row + 1) * params.destinations.size()); json_row.values.insert(json_row.values.end(), row_begin_iterator, row_end_iterator); matrix_json_array.values.push_back(json_row); } - json_result.values["distance_table"] = std::move(matrix_json_array); + result.values["distance_table"] = matrix_json_array; util::json::Array target_coord_json_array; for (const auto &phantom : snapped_target_phantoms) @@ -226,7 +176,7 @@ template class DistanceTablePlugin final : public BasePlugin json_coord.values.push_back(phantom.location.lon / COORDINATE_PRECISION); target_coord_json_array.values.push_back(json_coord); } - json_result.values["destination_coordinates"] = std::move(target_coord_json_array); + result.values["destination_coordinates"] = target_coord_json_array; util::json::Array source_coord_json_array; for (const auto &phantom : snapped_source_phantoms) { @@ -235,13 +185,9 @@ template class DistanceTablePlugin final : public BasePlugin json_coord.values.push_back(phantom.location.lon / COORDINATE_PRECISION); source_coord_json_array.values.push_back(json_coord); } - json_result.values["source_coordinates"] = std::move(source_coord_json_array); + result.values["source_coordinates"] = source_coord_json_array; return Status::Ok; } - - private: - std::string descriptor_string; - DataFacadeT *facade; }; } } diff --git a/include/engine/routing_algorithms/many_to_many.hpp b/include/engine/routing_algorithms/many_to_many.hpp index 016b5e94b..d4c05c6ac 100644 --- a/include/engine/routing_algorithms/many_to_many.hpp +++ b/include/engine/routing_algorithms/many_to_many.hpp @@ -44,8 +44,6 @@ class ManyToManyRouting final { } - ~ManyToManyRouting() {} - std::shared_ptr> operator()(const std::vector &phantom_sources_array, const std::vector &phantom_targets_array) const diff --git a/include/osrm/osrm.hpp b/include/osrm/osrm.hpp index 1d28787f3..1dccecfa9 100644 --- a/include/osrm/osrm.hpp +++ b/include/osrm/osrm.hpp @@ -49,24 +49,30 @@ struct EngineConfig; namespace api { struct RouteParameters; +struct TableParameters; } } using engine::EngineConfig; using engine::api::RouteParameters; +using engine::api::TableParameters; namespace json = util::json; class OSRM { + public: + explicit OSRM(EngineConfig &config); + ~OSRM(); + + OSRM(OSRM &&) noexcept; + OSRM &operator=(OSRM &&) noexcept; + + Status Route(const RouteParameters ¶meters, json::Object &result); + Status Table(const TableParameters ¶meters, json::Object &result); + private: std::unique_ptr engine_; - - public: - OSRM(EngineConfig &lib_config); - ~OSRM(); // needed for unique_ptr + impl abstraction - Status Route(const RouteParameters &route_parameters, json::Object &json_result); }; - } #endif // OSRM_HPP diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 48c1a72e5..2a4f738a9 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -3,7 +3,7 @@ #include "engine/api/route_parameters.hpp" #include "engine/status.hpp" -//#include "engine/plugins/distance_table.hpp" +#include "engine/plugins/distance_table.hpp" //#include "engine/plugins/hello_world.hpp" //#include "engine/plugins/nearest.hpp" //#include "engine/plugins/timestamp.hpp" @@ -35,59 +35,15 @@ namespace osrm { namespace engine { - -// Abstracted away the query locking into a template function -// Works the same for every plugin. -template -Status RunQuery(const std::unique_ptr &lock, - datafacade::BaseDataFacade &facade, - const ParameterT ¶meters, - PluginT &plugin, - util::json::Object &json_result) +struct Engine::EngineLock { - if (!lock) - { - return plugin.HandleRequest(parameters, json_result); - } - - BOOST_ASSERT(lock); - lock->IncreaseQueryCount(); - - auto& shared_facade = static_cast(facade); - shared_facade.CheckAndReloadFacade(); - // Get a shared data lock so that other threads won't update - // things while the query is running - boost::shared_lock data_lock{shared_facade.data_mutex}; - - Status status = plugin.HandleRequest(parameters, json_result); - - lock->DecreaseQueryCount(); - return status; -} - - -Engine::Engine(EngineConfig &config) -{ - if (config.use_shared_memory) - { - lock = util::make_unique(); - query_data_facade = util::make_unique(); - } - else - { - // populate base path - util::populate_base_path(config.server_paths); - query_data_facade = util::make_unique(config.server_paths); - } - - route_plugin = util::make_unique(*query_data_facade, config.max_locations_viaroute); -} - -Status Engine::Route(const api::RouteParameters &route_parameters, - util::json::Object &result) -{ - return RunQuery(lock, *query_data_facade, route_parameters, *route_plugin, result); -} + // will only be initialized if shared memory is used + storage::SharedBarriers barrier; + // decrease number of concurrent queries + void DecreaseQueryCount(); + // increase number of concurrent queries + void IncreaseQueryCount(); +}; // decrease number of concurrent queries void Engine::EngineLock::DecreaseQueryCount() @@ -124,5 +80,65 @@ void Engine::EngineLock::IncreaseQueryCount() // increment query count ++(barrier.number_of_queries); } +} // ns engine +} // ns osrm + +namespace +{ +// Abstracted away the query locking into a template function +// Works the same for every plugin. +template +osrm::engine::Status RunQuery(const std::unique_ptr &lock, + osrm::engine::datafacade::BaseDataFacade &facade, + const ParameterT ¶meters, + PluginT &plugin, + osrm::util::json::Object &json_result) +{ + if (!lock) + { + return plugin.HandleRequest(parameters, json_result); + } + + BOOST_ASSERT(lock); + lock->IncreaseQueryCount(); + + auto &shared_facade = static_cast(facade); + shared_facade.CheckAndReloadFacade(); + // Get a shared data lock so that other threads won't update + // things while the query is running + boost::shared_lock data_lock{shared_facade.data_mutex}; + + osrm::engine::Status status = plugin.HandleRequest(parameters, json_result); + + lock->DecreaseQueryCount(); + return status; } +} // anon. ns + +namespace osrm +{ +namespace engine +{ +Engine::Engine(EngineConfig &config) +{ + if (config.use_shared_memory) + { + lock = util::make_unique(); + query_data_facade = util::make_unique(); + } + else + { + util::populate_base_path(config.server_paths); + query_data_facade = util::make_unique(config.server_paths); + } + + route_plugin = util::make_unique(*query_data_facade, + config.max_locations_viaroute); } + +Status Engine::Route(const api::RouteParameters &route_parameters, util::json::Object &result) +{ + return RunQuery(lock, *query_data_facade, route_parameters, *route_plugin, result); +} +} // engine ns +} // osrm ns diff --git a/src/osrm/osrm.cpp b/src/osrm/osrm.cpp index 35dc46949..54111c505 100644 --- a/src/osrm/osrm.cpp +++ b/src/osrm/osrm.cpp @@ -1,23 +1,31 @@ #include "osrm/osrm.hpp" +#include "engine/api/route_parameters.hpp" +#include "engine/api/table_parameters.hpp" #include "engine/engine.hpp" #include "engine/status.hpp" #include "engine/engine_config.hpp" -#include "engine/plugins/viaroute.hpp" -#include "storage/shared_barriers.hpp" #include "util/make_unique.hpp" namespace osrm { -// proxy code for compilation firewall -OSRM::OSRM(engine::EngineConfig &config_) : engine_(util::make_unique(config_)) {} +// Pimpl idiom -// needed because unique_ptr needs the size of OSRM_impl for delete -OSRM::~OSRM() {} +OSRM::OSRM(engine::EngineConfig &config) : engine_(util::make_unique(config)) {} +OSRM::~OSRM() = default; +OSRM::OSRM(OSRM &&) noexcept = default; +OSRM &OSRM::operator=(OSRM &&) noexcept = default; -engine::Status OSRM::Route(const RouteParameters &route_parameters, util::json::Object &json_result) +// Forward to implementation + +engine::Status OSRM::Route(const engine::api::RouteParameters ¶ms, util::json::Object &result) { - return engine_->Route(route_parameters, json_result); + return engine_->Route(params, result); } +engine::Status OSRM::Table(const engine::api::TableParameters ¶ms, json::Object &result) +{ + return engine_->Table(params, result); } + +} // ns osrm