Skip to content

Commit f0c6ad7

Browse files
committed
first draft of thor service layer
1 parent e900a2a commit f0c6ad7

File tree

9 files changed

+285
-15
lines changed

9 files changed

+285
-15
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ libtool
3030
# built objects
3131
pathtest
3232
citytest
33+
thor_service
3334
*.o
3435
.deps/
3536
.dirstamp

Makefile.am

+15-8
Original file line numberDiff line numberDiff line change
@@ -43,29 +43,36 @@ nobase_include_HEADERS = \
4343
valhalla/thor/edgestatus.h \
4444
valhalla/thor/pathalgorithm.h \
4545
valhalla/thor/pathinfo.h \
46-
valhalla/thor/trippathbuilder.h
46+
valhalla/thor/trippathbuilder.h \
47+
valhalla/thor/service.h
4748
libvalhalla_thor_la_SOURCES = \
4849
src/thor/adjacencylist.cc \
4950
src/thor/astarheuristic.cc \
5051
src/thor/edgestatus.cc \
5152
src/thor/formlocalpath.cc \
5253
src/thor/pathalgorithm.cc \
53-
src/thor/trippathbuilder.cc
54+
src/thor/trippathbuilder.cc \
55+
src/thor/service.cc
5456
libvalhalla_thor_la_CPPFLAGS = $(DEPS_CFLAGS) $(VALHALLA_CPPFLAGS) @BOOST_CPPFLAGS@
55-
libvalhalla_thor_la_LIBADD = $(DEPS_LIBS) $(VALHALLA_LDFLAGS) @BOOST_PROGRAM_OPTIONS_LIB@ @BOOST_FILESYSTEM_LIB@ @PROTOC_LIBS@
57+
libvalhalla_thor_la_LIBADD = $(DEPS_LIBS) $(VALHALLA_LDFLAGS) $(BOOST_PROGRAM_OPTIONS_LIB) $(BOOST_FILESYSTEM_LIB) $(BOOST_SYSTEM_LIB) $(BOOST_THREAD_LIB) @PROTOC_LIBS@
5658

5759
#distributed executables
58-
bin_PROGRAMS = pathtest \
59-
citytest
60-
60+
bin_PROGRAMS = \
61+
pathtest \
62+
citytest \
63+
thor_service
6164
pathtest_SOURCES = \
6265
src/thor/pathtest/pathtest.cc
6366
pathtest_CPPFLAGS = $(DEPS_CFLAGS) $(VALHALLA_CPPFLAGS) @BOOST_CPPFLAGS@
64-
pathtest_LDADD = $(DEPS_LIBS) $(VALHALLA_LDFLAGS) @BOOST_LDFLAGS@ @BOOST_PROGRAM_OPTIONS_LIB@ @BOOST_FILESYSTEM_LIB@ -lz libvalhalla_thor.la
67+
pathtest_LDADD = $(DEPS_LIBS) $(VALHALLA_LDFLAGS) @BOOST_LDFLAGS@ $(BOOST_PROGRAM_OPTIONS_LIB) $(BOOST_FILESYSTEM_LIB) -lz libvalhalla_thor.la
6568
citytest_SOURCES = \
6669
src/thor/citytest/citytest.cc
6770
citytest_CPPFLAGS = $(DEPS_CFLAGS) $(VALHALLA_CPPFLAGS) @BOOST_CPPFLAGS@
68-
citytest_LDADD = $(DEPS_LIBS) $(VALHALLA_LDFLAGS) @BOOST_LDFLAGS@ @BOOST_PROGRAM_OPTIONS_LIB@ @BOOST_FILESYSTEM_LIB@ -lz libvalhalla_thor.la
71+
citytest_LDADD = $(DEPS_LIBS) $(VALHALLA_LDFLAGS) @BOOST_LDFLAGS@ $(BOOST_PROGRAM_OPTIONS_LIB) $(BOOST_FILESYSTEM_LIB) -lz libvalhalla_thor.la
72+
thor_service_SOURCES = \
73+
src/thor/thor_service.cc
74+
thor_service_CPPFLAGS = $(DEPS_CFLAGS) $(VALHALLA_CPPFLAGS) @BOOST_CPPFLAGS@
75+
thor_service_LDADD = $(DEPS_LIBS) $(VALHALLA_LDFLAGS) @BOOST_LDFLAGS@ $(BOOST_PROGRAM_OPTIONS_LIB) $(BOOST_FILESYSTEM_LIB) $(BOOST_SYSTEM_LIB) $(BOOST_THREAD_LIB) -lz libvalhalla_thor.la
6976

7077
# tests
7178
check_PROGRAMS = \

circle.yml

+5-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
machine:
2+
environment:
3+
LD_LIBRARY_PATH: .:`cat /etc/ld.so.conf.d/* | grep -v -E "#" | tr "\\n" ":" | sed -e "s/:$//g"`
24
pre:
35
- sudo add-apt-repository -y ppa:boost-latest/ppa
46
#- sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
@@ -16,14 +18,15 @@ dependencies:
1618
- sudo apt-get remove --purge -y libboost*
1719
- sudo apt-get install -y autoconf automake libtool make gcc-4.8 g++-4.8 libboost1.54-dev libboost-program-options1.54-dev libboost-filesystem1.54-dev libboost-system1.54-dev lcov protobuf-compiler libprotobuf-dev lua5.2 liblua5.2-dev
1820
- sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 90
21+
- scripts/install_service_deps.sh
1922
#valhalla dependencies
2023
- cd deps; for dep in midgard baldr sif mjolnir loki odin; do cd $dep; ./autogen.sh && ./configure && sudo make -j4 install; cd ..; done
2124

2225
test:
2326
pre:
24-
- ./autogen.sh && ./configure --enable-coverage --with-valhalla-midgard=/usr/local --with-valhalla-baldr=/usr/local --with-valhalla-loki=/usr/local --with-valhalla-odin=/usr/local --with-valhalla-sif=/usr/local --with-valhalla-mjolnir=/usr/local
27+
- ./autogen.sh && ./configure --enable-coverage --with-valhalla-midgard=/usr/local --with-valhalla-baldr=/usr/local --with-valhalla-loki=/usr/local --with-valhalla-odin=/usr/local --with-valhalla-sif=/usr/local --with-valhalla-mjolnir=/usr/local CPPFLAGS=-DBOOST_SPIRIT_THREADSAFE
2528
override:
26-
- LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib make test -j4
29+
- make test -j4
2730
post:
2831
- sudo make install
2932

conf/valhalla.json

+33-3
Original file line numberDiff line numberDiff line change
@@ -15,25 +15,55 @@
1515
"node_script": "conf/vertices.lua",
1616
"node_function": "nodes_proc",
1717
"way_script": "conf/edges.lua",
18-
"way_function": "ways_proc"
18+
"way_function": "ways_proc",
19+
"relation_script": "conf/relations.lua",
20+
"relation_function": "rels_proc"
1921
},
2022
"logging": {
2123
"type": "std_out",
2224
"color": true
2325
}
2426
},
27+
"loki": {
28+
"logging": {
29+
"type": "std_out",
30+
"color": true
31+
},
32+
"service": {
33+
"proxy": "ipc://loki"
34+
}
35+
},
2536
"thor": {
2637
"logging": {
2738
"type": "std_out",
2839
"color": true
40+
},
41+
"service": {
42+
"proxy": "ipc://thor"
43+
}
44+
},
45+
"odin": {
46+
"logging": {
47+
"type": "std_out",
48+
"color": true
49+
},
50+
"service": {
51+
"proxy": "ipc://odin"
2952
}
3053
},
3154
"tyr": {
32-
"listen_address": "0.0.0.0",
33-
"port": 8003,
3455
"logging": {
3556
"type": "std_out",
3657
"color": true
58+
},
59+
"service": {
60+
"proxy": "ipc://tyr"
61+
}
62+
},
63+
"httpd": {
64+
"service": {
65+
"listen": "tcp://*:8002",
66+
"loopback": "ipc://loopback"
3767
}
3868
},
3969
"costing_options": {

configure.ac

+3-2
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,11 @@ CHECK_VALHALLA_ODIN
3535
AX_BOOST_BASE([1.54], , [AC_MSG_ERROR([cannot find Boost libraries, which are are required for building thor. Please install libboost-dev.])])
3636
AX_BOOST_PROGRAM_OPTIONS
3737
AX_BOOST_SYSTEM
38+
AX_BOOST_THREAD
3839
AX_BOOST_FILESYSTEM
3940

40-
# check pkg-config packaged packages.
41-
PKG_CHECK_MODULES([DEPS], [protobuf >= 2.4.0])
41+
# check pkg-config dependencies
42+
PKG_CHECK_MODULES([DEPS], [protobuf >= 2.4.0 libzmq >= 4.0 libprime_server >= 0.1.0])
4243

4344
# optionally enable coverage information
4445
CHECK_COVERAGE

scripts/install_service_deps.sh

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#!/bin/bash
2+
set -e
3+
4+
# grab the latest zmq library:
5+
git clone --depth=1 --recurse-submodules --single-branch --branch=master https://github.com/zeromq/libzmq.git
6+
pushd libzmq
7+
./autogen.sh && ./configure --without-libsodium --without-documentation && make -j4
8+
sudo make install
9+
popd
10+
rm -rf libzmq
11+
12+
# grab experimental zmq-based server API:
13+
git clone --depth=1 --recurse-submodules --single-branch --branch=master https://github.com/kevinkreiser/prime_server.git
14+
pushd prime_server
15+
./autogen.sh && ./configure && make test -j4
16+
sudo make install
17+
popd
18+
rm -rf prime_server

src/thor/service.cc

+171
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
#include <functional>
2+
#include <string>
3+
#include <stdexcept>
4+
#include <vector>
5+
#include <unordered_map>
6+
#include <cstdint>
7+
#include <sstream>
8+
#include <boost/property_tree/ptree.hpp>
9+
#include <boost/property_tree/info_parser.hpp>
10+
11+
#include <prime_server/prime_server.hpp>
12+
#include <prime_server/http_protocol.hpp>
13+
using namespace prime_server;
14+
15+
#include <valhalla/midgard/logging.h>
16+
#include <valhalla/baldr/json.h>
17+
#include <valhalla/baldr/location.h>
18+
#include <valhalla/baldr/pathlocation.h>
19+
#include <valhalla/baldr/graphreader.h>
20+
#include <valhalla/sif/costfactory.h>
21+
#include <valhalla/sif/autocost.h>
22+
#include <valhalla/sif/bicyclecost.h>
23+
#include <valhalla/sif/pedestriancost.h>
24+
25+
#include "thor/service.h"
26+
#include "thor/trippathbuilder.h"
27+
#include "thor/pathalgorithm.h"
28+
29+
using namespace valhalla;
30+
using namespace valhalla::midgard;
31+
using namespace valhalla::baldr;
32+
using namespace valhalla::sif;
33+
34+
35+
namespace {
36+
//TODO: throw this in the header to make it testable?
37+
class thor_worker_t {
38+
public:
39+
thor_worker_t(const boost::property_tree::ptree& config):config(config),
40+
origin(PointLL()), destination(PointLL()), reader(config.get_child("mjolnir.hierarchy")) {
41+
// Register edge/node costing methods
42+
factory.Register("auto", sif::CreateAutoCost);
43+
factory.Register("auto_shorter", sif::CreateAutoShorterCost);
44+
factory.Register("bicycle", sif::CreateBicycleCost);
45+
factory.Register("pedestrian", sif::CreatePedestrianCost);
46+
}
47+
worker_t::result_t work(const std::list<zmq::message_t>& job, void* request_info) {
48+
try{
49+
//get some info about what we need to do
50+
std::string request_str(static_cast<const char*>(job.front().data()), job.front().size());
51+
std::stringstream stream(request_str);
52+
boost::property_tree::ptree request;
53+
boost::property_tree::read_info(stream, request);
54+
init_request(request);
55+
56+
//find a path
57+
auto path_edges = path_algorithm.GetBestPath(origin, destination, reader, cost);
58+
if (path_edges.size() == 0) {
59+
if (cost->AllowMultiPass()) {
60+
LOG_INFO("Try again with relaxed hierarchy limits");
61+
path_algorithm.Clear();
62+
cost->RelaxHierarchyLimits(16.0f);
63+
path_edges = path_algorithm.GetBestPath(origin, destination, reader, cost);
64+
}
65+
}
66+
if (path_edges.size() == 0) {
67+
cost->DisableHighwayTransitions();
68+
path_edges = path_algorithm.GetBestPath(origin, destination, reader, cost);
69+
if (path_edges.size() == 0) {
70+
throw std::runtime_error("No path could be found for input");
71+
}
72+
}
73+
74+
// Form output information based on path edges
75+
auto trip_path = thor::TripPathBuilder::Build(reader, path_edges, origin, destination);
76+
path_algorithm.Clear();
77+
locations.clear();
78+
79+
//pass it on
80+
worker_t::result_t result{true};
81+
result.messages.emplace_back(std::move(request_str)); //the original request
82+
result.messages.emplace_back(trip_path.SerializeAsString()); //the protobuf path
83+
return result;
84+
}
85+
catch(const std::exception& e) {
86+
worker_t::result_t result{false};
87+
http_response_t response(400, "Bad Request", e.what());
88+
response.from_info(static_cast<http_request_t::info_t*>(request_info));
89+
result.messages.emplace_back(response.to_string());
90+
return result;
91+
}
92+
}
93+
void init_request(const boost::property_tree::ptree& request) {
94+
//we require locations
95+
try {
96+
for(const auto& location : request.get_child("locations"))
97+
locations.push_back(baldr::Location::FromPtree(location.second));
98+
if(locations.size() < 2)
99+
throw;
100+
//TODO: bail if this is too many
101+
}
102+
catch(...) {
103+
throw std::runtime_error("insufficiently specified required parameter 'locations'");
104+
}
105+
106+
//we require correlated locations
107+
try {
108+
auto origin_pt = request.get_child("origin");
109+
origin = PathLocation::FromPtree(locations, origin_pt);
110+
auto destination_pt = request.get_child("destination");
111+
destination = PathLocation::FromPtree(locations, destination_pt);
112+
}
113+
catch(...) {
114+
throw std::runtime_error("path computation requires graph correlated locations");
115+
}
116+
117+
// Parse out the type of route - this provides the costing method to use
118+
std::string costing;
119+
try {
120+
costing = request.get<std::string>("costing");
121+
}
122+
catch(...) {
123+
throw std::runtime_error("No edge/node costing provided");
124+
}
125+
126+
// Get the costing options. Get the base options from the config and the
127+
// options for the specified costing method
128+
std::string method_options = "costing_options." + costing;
129+
boost::property_tree::ptree config_costing = config.get_child(method_options);
130+
const auto& request_costing = request.get_child_optional(method_options);
131+
if (request_costing) {
132+
// If the request has any options for this costing type, merge the 2
133+
// costing options - override any config options that are in the request.
134+
// and add any request options not in the config.
135+
for (const auto& r : *request_costing) {
136+
config_costing.put_child(r.first, r.second);
137+
}
138+
}
139+
cost = factory.Create(costing, config_costing);
140+
}
141+
protected:
142+
boost::property_tree::ptree config;
143+
std::vector<Location> locations;
144+
PathLocation origin, destination;
145+
sif::CostFactory<sif::DynamicCost> factory;
146+
valhalla::sif::cost_ptr_t cost;
147+
valhalla::baldr::GraphReader reader;
148+
valhalla::thor::PathAlgorithm path_algorithm;
149+
};
150+
}
151+
152+
namespace valhalla {
153+
namespace thor {
154+
void run_service(const boost::property_tree::ptree& config) {
155+
//gets requests from thor proxy
156+
auto upstream_endpoint = config.get<std::string>("thor.service.proxy") + "_out";
157+
//sends them on to odin
158+
auto downstream_endpoint = config.get<std::string>("odin.service.proxy") + "_in";
159+
//or returns just location information back to the server
160+
auto loopback_endpoint = config.get<std::string>("httpd.service.loopback");
161+
162+
//listen for requests
163+
zmq::context_t context;
164+
prime_server::worker_t worker(context, upstream_endpoint, downstream_endpoint, loopback_endpoint,
165+
std::bind(&thor_worker_t::work, thor_worker_t(config), std::placeholders::_1, std::placeholders::_2));
166+
worker.work();
167+
168+
//TODO: should we listen for SIGINT and terminate gracefully/exit(0)?
169+
}
170+
}
171+
}

src/thor/thor_service.cc

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#include <iostream>
2+
3+
#include <boost/property_tree/ptree.hpp>
4+
#include <boost/property_tree/json_parser.hpp>
5+
6+
#include "thor/service.h"
7+
8+
int main(int argc, char** argv) {
9+
10+
if(argc < 2) {
11+
std::cerr << "Usage: " << std::string(argv[0]) << " conf/valhalla.json" << std::endl;
12+
return 1;
13+
}
14+
15+
//config file
16+
std::string config_file(argv[1]);
17+
boost::property_tree::ptree config;
18+
boost::property_tree::read_json(config_file, config);
19+
20+
//run the service worker
21+
valhalla::thor::run_service(config);
22+
23+
return 0;
24+
}

valhalla/thor/service.h

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#ifndef __VALHALLA_THOR_SERVICE_H__
2+
#define __VALHALLA_THOR_SERVICE_H__
3+
4+
#include <boost/property_tree/ptree.hpp>
5+
6+
namespace valhalla {
7+
namespace thor {
8+
9+
void run_service(const boost::property_tree::ptree& config);
10+
11+
}
12+
}
13+
14+
15+
#endif //__VALHALLA_THOR_SERVICE_H__

0 commit comments

Comments
 (0)