Compare commits

...

30 Commits

Author SHA1 Message Date
Kajari Ghosh 31d8ff7a74 bump version to rc5 2018-12-04 14:19:23 -05:00
Daniel Paz-Soldan cb2532d0da Add node 10 builds to travis (#5246)
* Add node 10 builds to travis

* Add changelog
2018-12-04 14:18:31 -05:00
Kajari Ghosh e222fcfb17 remove destination/sources length <= coordinates length check (#5289) 2018-12-04 14:17:13 -05:00
Daniel Patterson 7a5b6dbede Bump version. 2018-11-02 01:43:15 -07:00
Daniel Patterson c08953c0e6 Merge branch 'master' into 5.20 2018-11-02 01:42:30 -07:00
Daniel Patterson 973837207b Merge pull request #5257 from Project-OSRM/danpat_table_noroute_estimate
Use estimates for NoRoute in table requests
2018-11-02 01:41:50 -07:00
Daniel Patterson 364e35af06 Remove estimated_cells value in the response. 2018-11-02 01:08:59 -07:00
Daniel Patterson 985ab58f45 Add feature to fill null table entries with as-the-crow-flies estimates. 2018-11-02 01:07:24 -07:00
Daniel Patterson e5a6c73fdf Prepare RC.1 2018-10-30 16:17:14 -07:00
Daniel Patterson cb1db646f2 Merge pull request #5251 from Project-OSRM/danpat_cache_distances
Pre-calculate distance values
2018-10-30 16:14:47 -07:00
Daniel Patterson a67c4bf84d Calculating durations is unavoidable due to tie-breaking minimums, but we can avoid accumulating distances if they're not requested. 2018-10-30 15:41:06 -07:00
Daniel Patterson 498259b220 Replace dynamic distance calculation for table plugin with pre-calculated distances on shortcuts, avoiding unpacking cost.
Adds approx 10% to total data size.  Speeds up large table requests by 2 orders of magnitude.

Co-authored-by: Kajari Ghosh <ghoshkaj@gmail.com>
2018-10-30 15:41:06 -07:00
Daniel Patterson 5327f8da4e Timer script should error properly if something goes wrong, and print out what happened. 2018-10-30 15:41:06 -07:00
Daniel Patterson 802ccfb497 Merge pull request #5252 from Project-OSRM/danpat_pin_yarn
Pin Yarn to 1.11.1 so it works with Node4
2018-10-30 15:40:19 -07:00
Daniel Patterson ec369d560a Pin Yarn to 1.11.1 so it works with Node4 (https://github.com/yarnpkg/yarn/pull/6409#issuecomment-429181371) 2018-10-30 15:38:55 -07:00
Daniel Patterson 535647e439 Merge pull request #5242 from Project-OSRM/ghoshkaj_mmaperize
Support directly mmap-ing datafiles
2018-10-29 11:58:26 -07:00
Daniel Patterson 954121634f Merge branch 'master' into ghoshkaj_mmaperize 2018-10-29 09:52:50 -07:00
Daniel Patterson 594a45e7e0 Re-use msinttypes bundled with RapidJSON when compiling on Windows. (#5249) 2018-10-29 09:51:56 -07:00
Daniel Patterson 96c7b47afe Document new mmap_memory option in NodeJS API 2018-10-27 00:12:17 -07:00
Daniel Patterson b7e7d32361 Expose new --mmap switch (mmap_memory: true in NodeJS), and run test suite in this mode, as well as shared memory mode. 2018-10-26 23:54:00 -07:00
Daniel Patterson 2f9cb44368 mmap tarfiles directly when mmapping is enabled, instead of copying data into separate mmapped block
Co-authored-by: Kajari Ghosh <ghoshkaj@gmail.com>
2018-10-26 23:53:59 -07:00
Daniel Patterson d80318f8ea Match serialized bit-packing for vector<bool> to match in-memory layout for vector_view<bool> so that data can be directly mmapped. 2018-10-26 23:53:50 -07:00
Daniel Paz-Soldan b1791d1ab3 Fix anchor links in api docs (#5235) 2018-10-16 09:23:29 -07:00
Yota Toyama a53da9095a Fix table node API docs (#5204) 2018-10-01 16:45:05 +03:00
Kajari Ghosh 72e03f9af9 update changelog after 5.19 release (#5203) 2018-09-11 00:34:40 -04:00
Kajari Ghosh 5597415f28 Revert "Improve speed of Map Matching" (#5196)
* Revert "Update changelog"

This reverts commit 9b779c704f.

* Revert "Fix formating"

This reverts commit 5bd7d04fe3.

* Revert "Fix bug in computation of distance offset for phantom node"

This reverts commit 0f78f7b2cc.

* Revert "Adjust text cases for flightly different matching due to rounding"

This reverts commit 8473be69d2.

* Revert "Round network distance to deci-meter to retain previous behavior"

This reverts commit c0124f7d77.

* Revert "Preserve heap state in map matching"

This reverts commit b630b4e32a.

* Revert "Use distance functions from many to many"

This reverts commit 89fabc1b9c.

* Revert "Use FCC algorithm for map matching distance calculation"

This reverts commit a649a8a5cf.
2018-09-06 12:05:28 -04:00
Jie 5476f6ab27 Fix GDB not work for osrm-routed on Linux (#5157)
As I mentioned in the issue #5156, I met below issue on my Win10+WSL(Ubuntu) env:
The remote debugger (VSCode on Win10, gdb on Ubuntu 18.04 LTS) works well from the beginning of the main() function. But when I step over the code pthread_sigmask(SIG_BLOCK, &new_mask, &old_mask); (src/tools/routed.cpp(289)), below breakpoints can not work and displayed unverified breakpoint.

Then I found that gdb breakpoint need at least SIGTRAP, SIGSTOP to work (Please refer to [how debugger works](http://www.alexonlinux.com/how-debugger-works) for more details), but all signals are blocked in the source code until server initialized done.

In my understanding, block all signals DO NOT make sense for this osrm-routed process. Only several signals (SIGINT, SIGQUIT, SIGTERM) are expected to wait. So I made the change and it works well for me then.
2018-09-05 16:23:48 -07:00
Daniel Patterson 0971f06193 Add option to node bindings to return result as a pre-generated JSON string (this avoids a lot of overhead, and moves JSON string rendering out of the main event loop). 2018-09-05 15:09:13 -07:00
Daniel Patterson 85515f063a Render floating point numbers to string using Grisu2 algorithmt instead of stdlib to speed up JSON generation. 2018-09-05 14:20:47 -07:00
Daniel Patterson 69d7825542 Increase allowed shared memory regions to 512 from ~120 2018-09-05 11:48:02 -07:00
103 changed files with 7185 additions and 2206 deletions
+57 -1
View File
@@ -154,6 +154,14 @@ matrix:
packages: ['g++-6', 'libbz2-dev', 'libxml2-dev', 'libzip-dev', 'liblua5.2-dev', 'libtbb-dev', 'libboost-all-dev', 'ccache']
env: CCOMPILER='gcc-6' CXXCOMPILER='g++-6' BUILD_TYPE='Release'
- os: osx
osx_image: xcode9.2
compiler: "mason-osx-release-node-10"
# we use the xcode provides clang and don't install our own
env: ENABLE_MASON=ON BUILD_TYPE='Release' CUCUMBER_TIMEOUT=60000 CCOMPILER='clang' CXXCOMPILER='clang++' ENABLE_ASSERTIONS=ON ENABLE_LTO=ON NODE="10"
after_success:
- ./scripts/travis/publish.sh
- os: osx
osx_image: xcode9.2
compiler: "mason-osx-release-node-8"
@@ -276,6 +284,54 @@ matrix:
after_success:
- ./scripts/travis/publish.sh
- os: linux
sudo: false
compiler: "node-10-mason-linux-release"
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['libstdc++-4.9-dev']
env: CLANG_VERSION='5.0.0' BUILD_TYPE='Release' ENABLE_MASON=ON ENABLE_LTO=ON JOBS=3 NODE="10"
install:
- pushd ${OSRM_BUILD_DIR}
- |
cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \
-DENABLE_MASON=${ENABLE_MASON:-OFF} \
-DENABLE_NODE_BINDINGS=${ENABLE_NODE_BINDINGS:-OFF} \
-DENABLE_CCACHE=ON \
-DCMAKE_INSTALL_PREFIX=${OSRM_INSTALL_DIR} \
-DENABLE_GLIBC_WORKAROUND=ON
- make --jobs=${JOBS}
- popd
script:
- npm run nodejs-tests
after_success:
- ./scripts/travis/publish.sh
- os: linux
sudo: false
compiler: "node-10-mason-linux-debug"
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['libstdc++-4.9-dev']
env: CLANG_VERSION='5.0.0' BUILD_TYPE='Debug' ENABLE_MASON=ON ENABLE_LTO=ON JOBS=3 NODE="10"
install:
- pushd ${OSRM_BUILD_DIR}
- |
cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \
-DENABLE_MASON=${ENABLE_MASON:-OFF} \
-DENABLE_NODE_BINDINGS=${ENABLE_NODE_BINDINGS:-OFF} \
-DENABLE_CCACHE=ON \
-DCMAKE_INSTALL_PREFIX=${OSRM_INSTALL_DIR} \
-DENABLE_GLIBC_WORKAROUND=ON
- make --jobs=${JOBS}
- popd
script:
- npm run nodejs-tests
after_success:
- ./scripts/travis/publish.sh
before_install:
- source $NVM_DIR/nvm.sh
- nvm install $NODE
@@ -296,7 +352,7 @@ before_install:
fi
- |
if [[ ! -f $(which yarn) ]]; then
npm install -g yarn
npm install -g yarn@1.11.1
fi
- export PACKAGE_JSON_VERSION=$(node -e "console.log(require('./package.json').version)")
- export PUBLISH=$([[ "${TRAVIS_TAG:-}" == "v${PACKAGE_JSON_VERSION}" ]] && echo "On" || echo "Off")
+25 -3
View File
@@ -1,10 +1,32 @@
# UNRELEASED
# 5.20.0
- Changes from 5.19.0:
- Table:
- CHANGED: switch to pre-calculated distances for table responses for large speedup and 10% memory increase. [#5251](https://github.com/Project-OSRM/osrm-backend/pull/5251)
- ADDED: new parameter `fallback_speed` which will fill `null` cells with estimated value [#5257](https://github.com/Project-OSRM/osrm-backend/pull/5257)
- CHANGED: Remove API check for matrix sources/destination length to be less than or equal to coordinates length. [#5298](https://github.com/Project-OSRM/osrm-backend/pull/5289)
- Features:
- ADDED: direct mmapping of datafiles is now supported via the `--mmap` switch. [#5242](https://github.com/Project-OSRM/osrm-backend/pull/5242)
- REMOVED: the previous `--memory_file` switch is now deprecated and will fallback to `--mmap` [#5242](https://github.com/Project-OSRM/osrm-backend/pull/5242)
- ADDED: all waypoints in responses now contain a `distance` property between the original coordinate and the snapped location. [#5255](https://github.com/Project-OSRM/osrm-backend/pull/5255)
- ADDED: Now publishing Node 10.x LTS binary modules [#5246](https://github.com/Project-OSRM/osrm-backend/pull/5246)
- Windows:
- FIXED: Windows builds again. [#5249](https://github.com/Project-OSRM/osrm-backend/pull/5249)
# 5.19.0
- Changes from 5.18.0:
- Optimizations:
- CHANGED: Map matching is now almost twice as fast. [#5060](https://github.com/Project-OSRM/osrm-backend/pull/5060)
- CHANGED: Use Grisu2 for serializing floating point numbers. [#5188](https://github.com/Project-OSRM/osrm-backend/pull/5188)
- ADDED: Node bindings can return pre-rendered JSON buffer. [#5189](https://github.com/Project-OSRM/osrm-backend/pull/5189)
- Profiles:
- CHANGED: Bicycle profile now blacklists barriers instead of whitelisting them [#5076
](https://github.com/Project-OSRM/osrm-backend/pull/5076/)
- CHANGED: Foot profile now blacklists barriers instead of whitelisting them [#5077
](https://github.com/Project-OSRM/osrm-backend/pull/5077/)
- CHANGED: Support maxlength and maxweight in car profile [#5101](https://github.com/Project-OSRM/osrm-backend/pull/5101]
- Bugfixes:
- FIXED: collapsing of ExitRoundabout instructions [#5114](https://github.com/Project-OSRM/osrm-backend/issues/5114)
- FIXED: negative distances in table plugin annotation [#5106](https://github.com/Project-OSRM/osrm-backend/issues/5106)
- Misc:
- CHANGED: Support up to 512 named shared memory regions [#5185](https://github.com/Project-OSRM/osrm-backend/pull/5185)
# 5.18.0
- Changes from 5.17.0:
+3 -2
View File
@@ -236,8 +236,9 @@ In addition to the [general options](#general-options) the following options are
|------------|--------------------------------------------------|---------------------------------------------|
|sources |`{index};{index}[;{index} ...]` or `all` (default)|Use location with given index as source. |
|destinations|`{index};{index}[;{index} ...]` or `all` (default)|Use location with given index as destination.|
|annotations |`duration` (default), `distance`, or `duration,distance`|Return the requested table or tables in response. Note that computing the `distances` table is currently only implemented for CH. If `annotations=distance` or `annotations=duration,distance` is requested when running a MLD router, a `NotImplemented` error will be returned.
|
|annotations |`duration` (default), `distance`, or `duration,distance`|Return the requested table or tables in response. Note that computing the `distances` table is currently only implemented for CH. If `annotations=distance` or `annotations=duration,distance` is requested when running a MLD router, a `NotImplemented` error will be returned. |
|fallback_speed|`double > 0`|If no route found between a source/destination pair, calculate the as-the-crow-flies distance, then use this speed to estimate duration.|
|fallback_coordinate|`input` (default), or `snapped`| When using a `fallback_speed`, use the user-supplied coordinate (`input`), or the snapped location (`snapped`) for calculating distances.|
Unlike other array encoded options, the length of `sources` and `destinations` can be **smaller or equal**
to number of input locations;
+44 -19
View File
@@ -25,7 +25,9 @@ var osrm = new OSRM('network.osrm');
Make sure you prepared the dataset with the correct toolchain.
- `options.shared_memory` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** Connects to the persistent shared memory datastore.
This requires you to run `osrm-datastore` prior to creating an `OSRM` object.
- `options.memory_file` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)?** Path to a file on disk to store the memory using mmap.
- `options.memory_file` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)?** *DEPRECATED*
Old behaviour: Path to a file on disk to store the memory using mmap. Current behaviour: setting this value is the same as setting `mmap_memory: true`.
- `options.mmap_memory` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** Map on-disk files to virtual memory addresses (mmap), rather than loading into RAM.
- `options.path` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)?** The path to the `.osrm` files. This is mutually exclusive with setting {options.shared_memory} to true.
- `options.max_locations_trip` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** Max. locations supported in trip query (default: unlimited).
- `options.max_locations_viaroute` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** Max. locations supported in viaroute query (default: unlimited).
@@ -56,7 +58,7 @@ Returns the fastest route between two or more coordinates while visiting the way
- `options.continue_straight` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** Forces the route to keep going straight at waypoints and don't do a uturn even if it would be faster. Default value depends on the profile.
- `options.approaches` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Keep waypoints on curb side. Can be `null` (unrestricted, default) or `curb`.
`null`/`true`/`false`
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)**
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)**
**Examples**
@@ -88,7 +90,7 @@ Note: `coordinates` in the general options only supports a single `{longitude},{
- `options.number` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)** Number of nearest segments that should be returned.
Must be an integer greater than or equal to `1`. (optional, default `1`)
- `options.approaches` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Keep waypoints on curb side. Can be `null` (unrestricted, default) or `curb`.
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)**
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)**
**Examples**
@@ -127,7 +129,9 @@ tables. Optionally returns distance table.
- `options.destinations` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** An array of `index` elements (`0 <= integer <
#coordinates`) to use location with given index as destination. Default is to use all.
- `options.approaches` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Keep waypoints on curb side. Can be `null` (unrestricted, default) or `curb`.
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)**
- `options.fallback_speed` **[Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)?** Replace `null` responses in result with as-the-crow-flies estimates based on `fallback_speed`. Value is in metres/second.
- `options.fallback_coordinate` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)?** Either `input` (default) or `snapped`. If using a `fallback_speed`, use either the user-supplied coordinate (`input`), or the snapped coordinate (`snapped`) for calculating the as-the-crow-flies diestance between two points.
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)**
**Examples**
@@ -167,7 +171,7 @@ and what weights they have applied.
- `ZXY` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)** an array consisting of `x`, `y`, and `z` values representing tile coordinates like
[wiki.openstreetmap.org/wiki/Slippy_map_tilenames](https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames)
and are supported by vector tile viewers like [Mapbox GL JS](https://www.mapbox.com/mapbox-gl-js/api/).
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)**
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)**
**Examples**
@@ -204,7 +208,7 @@ if they can not be matched successfully.
- `options.radiuses` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Standard deviation of GPS precision used for map matching. If applicable use GPS accuracy. Can be `null` for default value `5` meters or `double >= 0`.
- `options.gaps` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)?** Allows the input track splitting based on huge timestamp gaps between points. Either `split` or `ignore` (optional, default `split`).
- `options.tidy` **[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** Allows the input track modification to obtain better matching quality for noisy tracks (optional, default `false`).
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)**
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)**
**Examples**
@@ -268,7 +272,7 @@ Right now, the following combinations are possible:
- `options.source` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** Return route starts at `any` or `first` coordinate. (optional, default `any`)
- `options.destination` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** Return route ends at `any` or `last` coordinate. (optional, default `any`)
- `options.approaches` **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)?** Keep waypoints on curb side. Can be `null` (unrestricted, default) or `curb`.
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)**
- `callback` **[Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function)**
**Examples**
@@ -297,9 +301,30 @@ Returns **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refer
2) `waypoint_index`: index of the point in the trip.
**`trips`**: an array of [`Route`](#route) objects that assemble the trace.
## Responses
## Plugin behaviour
Responses
All plugins support a second additional object that is available to configure some NodeJS specific behaviours.
- `plugin_config` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** Object literal containing parameters for the trip query.
- `plugin_config.format` **[String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)?** The format of the result object to various API calls. Valid options are `object` (default), which returns a standard Javascript object, as described above, and `json_buffer`, which will return a NodeJS **[Buffer](https://nodejs.org/api/buffer.html)** object, containing a JSON string. The latter has the advantage that it can be immediately serialized to disk/sent over the network, and the generation of the string is performed outside the main NodeJS event loop. This option is ignored by the `tile` plugin.
**Examples**
```javascript
var osrm = new OSRM('network.osrm');
var options = {
coordinates: [
[13.36761474609375, 52.51663871100423],
[13.374481201171875, 52.506191342034576]
]
};
osrm.route(options, { format: "json_buffer" }, function(err, response) {
if (err) throw err;
console.log(response.toString("utf-8"));
});
```
## Responses
### Route
@@ -307,8 +332,8 @@ Represents a route through (potentially multiple) waypoints.
**Parameters**
- `exteral` **documentation** in
[`osrm-backend`](../http.md#route)
- **documentation** in
[`osrm-backend`](../http.md#route-object)
### RouteLeg
@@ -316,8 +341,8 @@ Represents a route between two waypoints.
**Parameters**
- `exteral` **documentation** in
[`osrm-backend`](../http.md#routeleg)
- **documentation** in
[`osrm-backend`](../http.md#routeleg-object)
### RouteStep
@@ -326,15 +351,15 @@ single way to the subsequent step.
**Parameters**
- `exteral` **documentation** in
[`osrm-backend`](https://github.com/Project-OSRM/osrm-backend/blob/master/docs/http.md#routestep)
- **documentation** in
[`osrm-backend`](../http.md#routestep-object)
### StepManeuver
**Parameters**
- `exteral` **documentation** in
[`osrm-backend`](https://github.com/Project-OSRM/osrm-backend/blob/master/docs/http.md#stepmaneuver)
- **documentation** in
[`osrm-backend`](../http.md#stepmaneuver-object)
### Waypoint
@@ -342,5 +367,5 @@ Object used to describe waypoint on a route.
**Parameters**
- `exteral` **documentation** in
[`osrm-backend`](https://github.com/Project-OSRM/osrm-backend/blob/master/docs/http.md#waypoint)
- **documentation** in
[`osrm-backend`](../http.md#waypoint-object)
+53 -3
View File
@@ -84,7 +84,47 @@ class OSRMDirectLoader extends OSRMBaseLoader {
throw new Error(util.format('osrm-routed %s: %s', errorReason(err), err.cmd));
}
});
callback();
this.child.readyFunc = (data) => {
if (/running and waiting for requests/.test(data)) {
this.child.stdout.removeListener('data', this.child.readyFunc);
callback();
}
};
this.child.stdout.on('data',this.child.readyFunc);
}
};
class OSRMmmapLoader extends OSRMBaseLoader {
constructor (scope) {
super(scope);
}
load (inputFile, callback) {
this.inputFile = inputFile;
this.shutdown(() => {
this.launch(callback);
});
}
osrmUp (callback) {
if (this.osrmIsRunning()) return callback(new Error("osrm-routed already running!"));
const command_arguments = util.format('%s -p %d -i %s -a %s --mmap', this.inputFile, this.scope.OSRM_PORT, this.scope.OSRM_IP, this.scope.ROUTING_ALGORITHM);
this.child = this.scope.runBin('osrm-routed', command_arguments, this.scope.environment, (err) => {
if (err && err.signal !== 'SIGINT') {
this.child = null;
throw new Error(util.format('osrm-routed %s: %s', errorReason(err), err.cmd));
}
});
this.child.readyFunc = (data) => {
if (/running and waiting for requests/.test(data)) {
this.child.stdout.removeListener('data', this.child.readyFunc);
callback();
}
};
this.child.stdout.on('data',this.child.readyFunc);
}
};
@@ -135,22 +175,32 @@ class OSRMLoader {
this.scope = scope;
this.sharedLoader = new OSRMDatastoreLoader(this.scope);
this.directLoader = new OSRMDirectLoader(this.scope);
this.mmapLoader = new OSRMmmapLoader(this.scope);
this.method = scope.DEFAULT_LOAD_METHOD;
}
load (inputFile, callback) {
if (!this.loader) {
this.loader = {shutdown: (cb) => cb() };
}
if (this.method === 'datastore') {
this.directLoader.shutdown((err) => {
this.loader.shutdown((err) => {
if (err) return callback(err);
this.loader = this.sharedLoader;
this.sharedLoader.load(inputFile, callback);
});
} else if (this.method === 'directly') {
this.sharedLoader.shutdown((err) => {
this.loader.shutdown((err) => {
if (err) return callback(err);
this.loader = this.directLoader;
this.directLoader.load(inputFile, callback);
});
} else if (this.method === 'mmap') {
this.loader.shutdown((err) => {
if (err) return callback(err);
this.loader = this.mmapLoader;
this.mmapLoader.load(inputFile, callback);
});
} else {
callback(new Error('*** Unknown load method ' + method));
}
+2 -2
View File
@@ -32,7 +32,7 @@ module.exports = function () {
this.DEFAULT_ENVIRONMENT = Object.assign({STXXLCFG: stxxl_config}, process.env);
this.DEFAULT_PROFILE = 'bicycle';
this.DEFAULT_INPUT_FORMAT = 'osm';
this.DEFAULT_LOAD_METHOD = 'datastore';
this.DEFAULT_LOAD_METHOD = process.argv[process.argv.indexOf('-m') +1].match('mmap') ? 'mmap' : 'datastore';
this.DEFAULT_ORIGIN = [1,1];
this.OSM_USER = 'osrm';
this.OSM_UID = 1;
@@ -80,7 +80,7 @@ module.exports = function () {
// eslint-disable-next-line no-console
console.info(util.format('Node Version', process.version));
if (parseInt(process.version.match(/v(\d)/)[1]) < 4) throw new Error('*** Please upgrade to Node 4.+ to run OSRM cucumber tests');
if (parseInt(process.version.match(/v(\d+)/)[1]) < 4) throw new Error('*** Please upgrade to Node 4.+ to run OSRM cucumber tests');
fs.exists(this.TEST_PATH, (exists) => {
if (exists)
+235 -135
View File
@@ -5,21 +5,49 @@ Feature: Basic Distance Matrix
Background:
Given the profile "testbot"
And the partition extra arguments "--small-component-size 1 --max-cell-sizes 2,4,8,16"
Scenario: Testbot - Travel distance matrix of minimal network
Scenario: Testbot - Travel distance matrix of small grid
Given the node map
"""
a b
a b c
d e f
"""
And the ways
| nodes |
| ab |
| abc |
| def |
| ad |
| be |
| cf |
When I request a travel distance matrix I should get
| | a | b |
| a | 0 | 100+-1 |
| b | 100+-1 | 0 |
| | a | b | e | f |
| a | 0 | 100.1 | 199.5 | 299.5 |
| b | 100.1 | 0 | 99.4 | 199.5 |
| e | 199.5 | 99.4 | 0 | 100.1 |
| f | 299.5 | 199.5 | 100.1 | 0 |
Scenario: Testbot - Travel distance matrix of minimal network exact distances
Given the node map
"""
a z
b
c
d
"""
And the ways
| nodes |
| az |
| zbcd |
When I request a travel distance matrix I should get
| | a | z | b | c | d |
| a | 0 | 100.1 | 199.5 | 298.9 | 398.3 |
| z | 100.1 | 0 | 99.4 | 198.8 | 298.2 |
| b | 199.5 | 99.4 | 0 | 99.4 | 198.8 |
| c | 298.9 | 198.8 | 99.4 | 0 | 99.4 |
| d | 398.3 | 298.2 | 198.8 | 99.4 | 0 |
Scenario: Testbot - Travel distance matrix of minimal network with toll exclude
Given the query options
@@ -39,11 +67,11 @@ Feature: Basic Distance Matrix
| bd | motorway | yes | not drivable for exclude=toll and exclude=motorway,toll |
When I request a travel distance matrix I should get
| | a | b | c | d |
| a | 0 | 100+-1 | | |
| b | 100+-1 | 0 | | |
| c | | | 0 | 100+-1 |
| d | | | 100+-1 | 0 |
| | a | b | c | d |
| a | 0 | 100.1 | | |
| b | 100.1 | 0 | | |
| c | | | 0 | 100.1 |
| d | | | 100.1 | 0 |
Scenario: Testbot - Travel distance matrix of minimal network with motorway exclude
Given the query options
@@ -63,8 +91,8 @@ Feature: Basic Distance Matrix
| bd | residential | |
When I request a travel distance matrix I should get
| | a | b | c | d |
| a | 0 | 300+-2 | 100+-2 | 200+-2 |
| | a | b | c | d |
| a | 0 | 298.9 | 99.4 | 199.5 |
Scenario: Testbot - Travel distance matrix of minimal network disconnected motorway exclude
Given the query options
@@ -84,8 +112,8 @@ Feature: Basic Distance Matrix
| efgh | residential | |
When I request a travel distance matrix I should get
| | a | b | e |
| a | 0 | 50+-1 | |
| | a | b | e |
| a | 0 | 50.1 | |
Scenario: Testbot - Travel distance matrix of minimal network with motorway and toll excludes
Given the query options
@@ -106,7 +134,7 @@ Feature: Basic Distance Matrix
When I request a travel distance matrix I should get
| | a | b | e | g |
| a | 0 | 100+-1 | | |
| a | 0 | 100.1 | | |
Scenario: Testbot - Travel distance matrix with different way speeds
Given the node map
@@ -121,22 +149,22 @@ Feature: Basic Distance Matrix
| cd | tertiary |
When I request a travel distance matrix I should get
| | a | b | c | d |
| a | 0 | 100+-1 | 200+-1 | 300+-1 |
| b | 100+-1 | 0 | 100+-1 | 200+-1 |
| c | 200+-1 | 100+-1 | 0 | 100+-1 |
| d | 300+-1 | 200+-1 | 100+-1 | 0 |
| | a | b | c | d |
| a | 0 | 100.1 | 200.1 | 300.2 |
| b | 100.1 | 0 | 100.1 | 200.1 |
| c | 200.1 | 100.1 | 0 | 100.1 |
| d | 300.2 | 200.1 | 100.1 | 0 |
When I request a travel distance matrix I should get
| | a | b | c | d |
| a | 0 | 100+-1 | 200+-1 | 300+-1 |
| | a | b | c | d |
| a | 0 | 100.1 | 200.1 | 300.2 |
When I request a travel distance matrix I should get
| | a |
| a | 0 |
| b | 100+-1 |
| c | 200+-1 |
| d | 300+-1 |
| | a |
| a | 0 |
| b | 100.1 |
| c | 200.1 |
| d | 300.2 |
Scenario: Testbot - Travel distance matrix of small grid
Given the node map
@@ -154,11 +182,11 @@ Feature: Basic Distance Matrix
| cf |
When I request a travel distance matrix I should get
| | a | b | e | f |
| a | 0 | 100+-1 | 200+-1 | 300+-1 |
| b | 100+-1 | 0 | 100+-1 | 200+-1 |
| e | 200+-1 | 100+-1 | 0 | 100+-1 |
| f | 300+-1 | 200+-1 | 100+-1 | 0 |
| | a | b | e | f |
| a | 0 | 100.1 | 199.5 | 299.5 |
| b | 100.1 | 0 | 99.4 | 199.5 |
| e | 199.5 | 99.4 | 0 | 100.1 |
| f | 299.5 | 199.5 | 100.1 | 0 |
Scenario: Testbot - Travel distance matrix of network with unroutable parts
Given the node map
@@ -172,7 +200,7 @@ Feature: Basic Distance Matrix
When I request a travel distance matrix I should get
| | a | b |
| a | 0 | 100+-1 |
| a | 0 | 100.1 |
| b | | 0 |
Scenario: Testbot - Travel distance matrix of network with oneways
@@ -189,11 +217,11 @@ Feature: Basic Distance Matrix
| by | |
When I request a travel distance matrix I should get
| | x | y | d | e |
| x | 0 | 300+-2 | 400+-2 | 300+-2 |
| y | 500+-2 | 0 | 300+-2 | 200+-2 |
| d | 200+-2 | 300+-2 | 0 | 300+-2 |
| e | 300+-2 | 400+-2 | 100+-2 | 0 |
| | x | y | d | e |
| x | 0 | 300.2 | 399.6 | 299.5 |
| y | 499 | 0 | 299.5 | 199.5 |
| d | 199.5 | 299.5 | 0 | 298.9 |
| e | 299.5 | 399.6 | 100.1 | 0 |
Scenario: Testbot - Rectangular travel distance matrix
Given the node map
@@ -212,53 +240,53 @@ Feature: Basic Distance Matrix
When I route I should get
| from | to | distance |
| e | a | 200m +- 1 |
| e | b | 100m +- 1 |
| f | a | 300m +- 1 |
| f | b | 200m +- 1 |
| e | a | 200m |
| e | b | 100m |
| f | a | 299.9m |
| f | b | 200m |
When I request a travel distance matrix I should get
| | a | b | e | f |
| a | 0 | 100+-1 | 200+-1 | 300+-1 |
| a | 0 | 100.1 | 199.5 | 299.5 |
When I request a travel distance matrix I should get
| | a |
| a | 0 |
| b | 100+-1 |
| e | 200+-1 |
| f | 300+-1 |
| | a |
| a | 0 |
| b | 100.1 |
| e | 199.5 |
| f | 299.5 |
When I request a travel distance matrix I should get
| | a | b | e | f |
| a | 0 | 100+-1 | 200+-1 | 300+-1 |
| b | 100+-1 | 0 | 100+-1 | 200+-1 |
| | a | b | e | f |
| a | 0 | 100.1 | 199.5 | 299.5 |
| b | 100.1 | 0 | 99.4 | 199.5 |
When I request a travel distance matrix I should get
| | a | b |
| a | 0 | 100+-1 |
| b | 100+-1 | 0 |
| e | 200+-1 | 100+-1 |
| f | 300+-1 | 200+-1 |
| | a | b |
| a | 0 | 100.1 |
| b | 100.1 | 0 |
| e | 199.5 | 99.4 |
| f | 299.5 | 199.5 |
When I request a travel distance matrix I should get
| | a | b | e | f |
| a | 0 | 100+-1 | 200+-1 | 300+-1 |
| b | 100+-1 | 0 | 100+-1 | 200+-1 |
| e | 200+-1 | 100+-1 | 0 | 100+-1 |
| | a | b | e | f |
| a | 0 | 100.1 | 199.5 | 299.5 |
| b | 100.1 | 0 | 99.4 | 199.5 |
| e | 199.5 | 99.4 | 0 | 100.1 |
When I request a travel distance matrix I should get
| | a | b | e |
| a | 0 | 100+-1 | 200+-1 |
| b | 100+-1 | 0 | 100+-1 |
| e | 200+-1 | 100+-1 | 0 |
| f | 300+-1 | 200+-1 | 100+-1 |
| | a | b | e |
| a | 0 | 100.1 | 199.5 |
| b | 100.1 | 0 | 99.4 |
| e | 199.5 | 99.4 | 0 |
| f | 299.5 | 199.5 | 100.1 |
When I request a travel distance matrix I should get
| | a | b | e | f |
| a | 0 | 100+-1 | 200+-1 | 300+-1 |
| b | 100+-1 | 0 | 100+-1 | 200+-1 |
| e | 200+-1 | 100+-1 | 0 | 100+-1 |
| f | 300+-1 | 200+-1 | 100+-1 | 0 |
| | a | b | e | f |
| a | 0 | 100.1 | 199.5 | 299.5 |
| b | 100.1 | 0 | 99.4 | 199.5 |
| e | 199.5 | 99.4 | 0 | 100.1 |
| f | 299.5 | 199.5 | 100.1 | 0 |
Scenario: Testbot - Travel distance 3x2 matrix
Given the node map
@@ -277,9 +305,9 @@ Feature: Basic Distance Matrix
When I request a travel distance matrix I should get
| | b | e | f |
| a | 100+-1 | 200+-1 | 300+-1 |
| b | 0 | 100+-1 | 200+-1 |
| | b | e | f |
| a | 100.1 | 199.5 | 299.5 |
| b | 0 | 99.4 | 199.5 |
Scenario: Testbot - All coordinates are from same small component
Given a grid size of 300 meters
@@ -299,9 +327,9 @@ Feature: Basic Distance Matrix
| fg |
When I request a travel distance matrix I should get
| | f | g |
| f | 0 | 300+-2 |
| g | 300+-2 | 0 |
| | f | g |
| f | 0 | 298.2 |
| g | 298.2 | 0 |
Scenario: Testbot - Coordinates are from different small component and snap to big CC
Given a grid size of 300 meters
@@ -333,11 +361,11 @@ Feature: Basic Distance Matrix
| i | h | 300m |
When I request a travel distance matrix I should get
| | f | g | h | i |
| f | 0 | 300+-2 | 0 | 300+-2 |
| g | 300+-2 | 0 | 300+-2 | 0 |
| h | 0 | 300+-2 | 0 | 300+-2 |
| i | 300+-2 | 0 | 300+-2 | 0 |
| | f | g | h | i |
| f | 0 | 298.2 | 0 | 298.2 |
| g | 298.2 | 0 | 298.2 | 0 |
| h | 0 | 298.2 | 0 | 298.2 |
| i | 298.2 | 0 | 298.2 | 0 |
Scenario: Testbot - Travel distance matrix with loops
Given the node map
@@ -354,11 +382,11 @@ Feature: Basic Distance Matrix
| da | yes |
When I request a travel distance matrix I should get
| | 1 | 2 | 3 | 4 |
| 1 | 0 | 100+-1 | 400+-1 | 500+-1 |
| 2 | 700+-1 | 0 | 300+-1 | 400+-1 |
| 3 | 400+-1 | 500+-1 | 0 | 100+-1 |
| 4 | 300+-1 | 400+-1 | 700+-1 | 0 |
| | 1 | 2 | 3 | 4 |
| 1 | 0 | 100.1 | 399.6 | 499.7 |
| 2 | 699.1 | 0 | 299.5 | 399.6 |
| 3 | 399.6 | 499.7 | 0 | 100.1 |
| 4 | 299.5 | 399.6 | 699.1 | 0 |
Scenario: Testbot - Travel distance matrix based on segment durations
@@ -395,12 +423,12 @@ Feature: Basic Distance Matrix
| ce |
When I request a travel distance matrix I should get
| | a | b | c | d | e |
| a | 0 | 100+-2 | 200+-2 | 300+-2 | 400+-2 |
| b | 100+-2 | 0 | 100+-2 | 200+-2 | 300+-2 |
| c | 200+-2 | 100+-2 | 0 | 100+-2 | 200+-2 |
| d | 300+-2 | 200+-2 | 100+-2 | 0 | 300+-2 |
| e | 400+-2 | 300+-2 | 200+-2 | 300+-2 | 0 |
| | a | b | c | d | e |
| a | 0 | 100.1 | 200.1 | 300.2 | 398.9 |
| b | 100.1 | 0 | 100.1 | 200.1 | 298.9 |
| c | 200.1 | 100.1 | 0 | 100.1 | 198.8 |
| d | 300.2 | 200.1 | 100.1 | 0 | 298.9 |
| e | 398.9 | 298.9 | 198.8 | 298.9 | 0 |
Scenario: Testbot - Travel distance matrix for alternative loop paths
Given the profile file
@@ -439,26 +467,26 @@ Feature: Basic Distance Matrix
| ca | yes |
When I request a travel distance matrix I should get
| | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
| 1 | 0 | 1100+-5 | 300+-5 | 200+-5 | 600+-5 | 500+-5 | 900+-5 | 800+-5 |
| 2 | 100+-5 | 0 | 400+-5 | 300+-5 | 700+-5 | 600+-5 | 1000+-5 | 900+-5 |
| 3 | 900+-5 | 800+-5 | 0 | 1100+-5 | 300+-5 | 200+-5 | 600+-5 | 500+-5 |
| 4 | 1000+-5 | 900+-5 | 100+-5 | 0 | 400+-5 | 300+-5 | 700+-5 | 600+-5 |
| 5 | 600+-5 | 500+-5 | 900+-5 | 800+-5 | 0 | 1100+-5 | 300+-5 | 200+-5 |
| 6 | 700+-5 | 600+-5 | 1000+-5 | 900+-5 | 100+-5 | 0 | 400+-5 | 300+-5 |
| 7 | 300+-5 | 200+-5 | 600+-5 | 500+-5 | 900+-5 | 800+-5 | 0 | 1100+-5 |
| 8 | 400+-5 | 300+-5 | 700+-5 | 600+-5 | 1000+-5 | 900+-5 | 100+-5 | 0 |
| | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
| 1 | 0 | 1096.7 | 298.9 | 199.5 | 598.4 | 498.3 | 897.3 | 797.9 |
| 2 | 100.1 | 0 | 398.9 | 299.5 | 698.5 | 598.4 | 997.3 | 897.9 |
| 3 | 897.9 | 797.9 | 0 | 1097.4 | 299.5 | 199.5 | 598.4 | 499 |
| 4 | 997.3 | 897.3 | 99.4 | 0 | 398.9 | 298.9 | 697.8 | 598.4 |
| 5 | 598.4 | 498.3 | 897.3 | 797.9 | 0 | 1096.7 | 298.9 | 199.5 |
| 6 | 698.5 | 598.4 | 997.3 | 897.9 | 100.1 | 0 | 398.9 | 299.5 |
| 7 | 299.5 | 199.5 | 598.4 | 499 | 897.9 | 797.9 | 0 | 1097.4 |
| 8 | 398.9 | 298.9 | 697.8 | 598.4 | 997.3 | 897.3 | 99.4 | 0 |
When I request a travel distance matrix I should get
| | 1 |
| 1 | 0 |
| 2 | 100+-5 |
| 3 | 900+-5 |
| 4 | 1000+-5 |
| 5 | 600+-5 |
| 6 | 700+-5 |
| 7 | 300+-5 |
| 8 | 400+-5 |
| | 1 |
| 1 | 0 |
| 2 | 100.1 |
| 3 | 897.9 |
| 4 | 997.3 |
| 5 | 598.4 |
| 6 | 698.5 |
| 7 | 299.5 |
| 8 | 398.9 |
Scenario: Testbot - Travel distance matrix with ties
Given the node map
@@ -480,26 +508,26 @@ Feature: Basic Distance Matrix
| a | c | ac,ac | 200m | 20s | 20 |
When I route I should get
| from | to | route | distance |
| a | b | ab,ab | 450m |
| a | c | ac,ac | 200m |
| a | d | ac,dc,dc | 500m +- 1 |
| from | to | route | distance |
| a | b | ab,ab | 450m |
| a | c | ac,ac | 200m |
| a | d | ac,dc,dc | 499.9m |
When I request a travel distance matrix I should get
| | a | b | c | d |
| a | 0 | 450+-2 | 200+-2 | 500+-2 |
| | a | b | c | d |
| a | 0 | 450.3 | 198.8 | 499 |
When I request a travel distance matrix I should get
| | a |
| a | 0 |
| b | 450+-2 |
| c | 200+-2 |
| d | 500+-2 |
| | a |
| a | 0 |
| b | 450.3 |
| c | 198.8 |
| d | 499 |
When I request a travel distance matrix I should get
| | a | c |
| a | 0 | 200+-2 |
| c | 200+-2 | 0 |
| | a | c |
| a | 0 | 198.8 |
| c | 198.8 | 0 |
# Check rounding errors
@@ -515,8 +543,8 @@ Feature: Basic Distance Matrix
| abcd |
When I request a travel distance matrix I should get
| | a | b | c | d |
| a | 0 | 1000+-3 | 2000+-3 | 3000+-3 |
| | a | b | c | d |
| a | 0 | 1000.7 | 2001.4 | 3002.1 |
Scenario: Testbot - OneToMany vs ManyToOne
@@ -560,10 +588,82 @@ Feature: Basic Distance Matrix
| fd | |
When I request a travel distance matrix I should get
| | a | b | c | d | e | f |
| a | 0 | 100+-1 | 300+-1 | 650+-1 | 1930+-1 | 1533+-1 |
| b | 760+-1 | 0 | 200+-1 | 550+-1 | 1830+-1 | 1433+-1 |
| c | 560+-2 | 660+-2 | 0 | 350+-1 | 1630+-1 | 1233+-1 |
| d | 1480+-2 | 1580+-1 | 1780+-1 | 0 | 1280+-1 | 883+-1 |
| e | 200+-2 | 300+-2 | 500+-1 | 710+-1 | 0 | 1593+-1 |
| f | 597+-1 | 696+-1 | 896+-1 | 1108+-1 | 400+-3 | 0 |
| | a | b | c | d | e | f |
| a | 0 | 100.1 | 300.2 | 650.5 | 1930.6 | 1533 |
| b | 759 | 0 | 200.1 | 550.4 | 1830.5 | 1432.9 |
| c | 558.8 | 658.9 | 0 | 350.3 | 1630.4 | 1232.8 |
| d | 1478.9 | 1579 | 1779.1 | 0 | 1280.1 | 882.5 |
| e | 198.8 | 298.9 | 499 | 710.3 | 0 | 1592.8 |
| f | 596.4 | 696.5 | 896.6 | 1107.9 | 397.6 | 0 |
Scenario: Testbot - Filling in noroutes with estimates (defaults to input coordinate location)
Given a grid size of 300 meters
Given the extract extra arguments "--small-component-size 4"
Given the query options
| fallback_speed | 5 |
Given the node map
"""
a b f h 1
d e g i
"""
And the ways
| nodes |
| abeda |
| fhigf |
When I request a travel distance matrix I should get
| | a | b | f | 1 |
| a | 0 | 300.2 | 900.7 | 1501.1 |
| b | 300.2 | 0 | 600.5 | 1200.9 |
| f | 900.7 | 600.5 | 0 | 302.2 |
| 1 | 1501.1 | 1200.9 | 300.2 | 0 |
Scenario: Testbot - Filling in noroutes with estimates - use input coordinate
Given a grid size of 300 meters
Given the extract extra arguments "--small-component-size 4"
Given the query options
| fallback_speed | 5 |
| fallback_coordinate | input |
Given the node map
"""
a b f h 1
d e g i
"""
And the ways
| nodes |
| abeda |
| fhigf |
When I request a travel distance matrix I should get
| | a | b | f | 1 |
| a | 0 | 300.2 | 900.7 | 1501.1 |
| b | 300.2 | 0 | 600.5 | 1200.9 |
| f | 900.7 | 600.5 | 0 | 302.2 |
| 1 | 1501.1 | 1200.9 | 300.2 | 0 |
Scenario: Testbot - Filling in noroutes with estimates - use snapped coordinate
Given a grid size of 300 meters
Given the extract extra arguments "--small-component-size 4"
Given the query options
| fallback_speed | 5 |
| fallback_coordinate | snapped |
Given the node map
"""
a b f h 1
d e g i
"""
And the ways
| nodes |
| abeda |
| fhigf |
When I request a travel distance matrix I should get
| | a | b | f | 1 |
| a | 0 | 300.2 | 900.7 | 1200.9 |
| b | 300.2 | 0 | 600.5 | 900.7 |
| f | 900.7 | 600.5 | 0 | 302.2 |
| 1 | 1200.9 | 900.7 | 300.2 | 0 |
+71
View File
@@ -510,3 +510,74 @@ Feature: Basic Duration Matrix
| | a |
| a | 0 |
| b | 24.1 |
Scenario: Testbot - Filling in noroutes with estimates (defaults to input coordinate location)
Given a grid size of 300 meters
Given the extract extra arguments "--small-component-size 4"
Given the query options
| fallback_speed | 5 |
Given the node map
"""
a b f h 1
d e g i
"""
And the ways
| nodes |
| abeda |
| fhigf |
When I request a travel time matrix I should get
| | a | b | f | 1 |
| a | 0 | 30 | 18 | 30 |
| b | 30 | 0 | 12 | 24 |
| f | 18 | 12 | 0 | 30 |
| 1 | 30 | 24 | 30 | 0 |
Scenario: Testbot - Filling in noroutes with estimates - use input coordinate
Given a grid size of 300 meters
Given the extract extra arguments "--small-component-size 4"
Given the query options
| fallback_speed | 5 |
| fallback_coordinate | input |
Given the node map
"""
a b f h 1
d e g i
"""
And the ways
| nodes |
| abeda |
| fhigf |
When I request a travel time matrix I should get
| | a | b | f | 1 |
| a | 0 | 30 | 18 | 30 |
| b | 30 | 0 | 12 | 24 |
| f | 18 | 12 | 0 | 30 |
| 1 | 30 | 24 | 30 | 0 |
Scenario: Testbot - Filling in noroutes with estimates - use snapped coordinate
Given a grid size of 300 meters
Given the extract extra arguments "--small-component-size 4"
Given the query options
| fallback_speed | 5 |
| fallback_coordinate | snapped |
Given the node map
"""
a b f h 1
d e g i
"""
And the ways
| nodes |
| abeda |
| fhigf |
When I request a travel time matrix I should get
| | a | b | f | 1 |
| a | 0 | 30 | 18 | 24 |
| b | 30 | 0 | 12 | 18 |
| f | 18 | 12 | 0 | 30 |
| 1 | 24 | 18 | 30 | 0 |
+1 -1
View File
@@ -792,4 +792,4 @@ Feature: Basic Map Matching
When I match I should get
| trace | geometry | a:distance | a:duration | a:weight | duration |
| 2345 | 1.00018,1,1.000315,1 | 15.013264 | 1.5 | 1.5 | 1.5 |
| 4321 | 1.00027,1,1.000135,1 | 15.013264 | 1.5 | 1.5 | 1.5 |
| 4321 | 1.00027,1,1.000135,1 | 15.013264 | 1.5 | 1.5 | 1.5 |
+52 -54
View File
@@ -38,15 +38,15 @@ Feature: Multi level routing
Scenario: Testbot - Multi level routing
Given the node map
"""
ab ef
ab ef
\ /
dc hg
ij mn
lkpo
/ \
lkpo
"""
And the nodes
@@ -67,78 +67,76 @@ Feature: Multi level routing
When I route I should get
| from | to | route | time |
| a | b | abcda,abcda | 20s |
| a | f | abcda,cm,mnopm,kp,ijkli,hj,efghe,efghe | 229.4s |
| a | l | abcda,cm,mnopm,kp,ijkli,ijkli | 144.7s |
| a | o | abcda,cm,mnopm,mnopm,mnopm | 124.7s |
| f | l | efghe,hj,ijkli,ijkli,ijkli | 124.7s |
| f | o | efghe,hj,ijkli,kp,mnopm,mnopm | 144.7s |
| l | o | ijkli,kp,mnopm,mnopm | 60s |
| a | b | abcda,abcda | 25s |
| a | f | abcda,cm,mnopm,kp,ijkli,hj,efghe,efghe | 239.2s |
| a | l | abcda,cm,mnopm,kp,ijkli,ijkli | 157.1s |
| a | o | abcda,cm,mnopm,mnopm,mnopm | 137.1s |
| f | l | efghe,hj,ijkli,ijkli | 136.7s |
| f | o | efghe,hj,ijkli,kp,mnopm,mnopm | 162.1s |
| l | o | ijkli,kp,mnopm,mnopm | 80s |
| c | m | cm,cm | 44.7s |
| f | a | efghe,hj,ijkli,kp,mnopm,cm,abcda,abcda | 239.2s |
| l | a | ijkli,kp,mnopm,cm,abcda,abcda | 157.1s |
When I request a travel time matrix I should get
| | a | f | l | o |
| a | 0 | 229.4 | 144.7 | 124.7 |
| f | 229.4 | 0 | 124.7 | 144.7 |
| l | 144.7 | 124.7 | 0 | 60 |
| o | 124.7 | 144.7 | 60 | 0 |
| | a | f | l | o |
| a | 0 | 239.2 | 157.1 | 137.1 |
| f | 239.2 | 0 | 136.7 | 162.1 |
| l | 157.1 | 136.7 | 0 | 80 |
| o | 137.1 | 162.1 | 80 | 0 |
When I request a travel time matrix I should get
| | a | f | l | o |
| a | 0 | 229.4 | 144.7 | 124.7 |
| | a | f | l | o |
| a | 0 | 239.2 | 157.1 | 137.1 |
When I request a travel time matrix I should get
| | a |
| a | 0 |
| f | 229.4 |
| l | 144.7 |
| o | 124.7 |
| | a |
| a | 0 |
| f | 239.2 |
| l | 157.1 |
| o | 137.1 |
When I request a travel time matrix I should get
| | a | f | l | o |
| a | 0 | 229.4 | 144.7 | 124.7 |
| o | 124.7 | 144.7 | 60 | 0 |
| | a | f | l | o |
| a | 0 | 239.2 | 157.1 | 137.1 |
| o | 137.1 | 162.1 | 80 | 0 |
When I request a travel time matrix I should get
| | a | o |
| a | 0 | 124.7 |
| f | 229.4 | 144.7 |
| l | 144.7 | 60 |
| o | 124.7 | 0 |
| a | 0 | 137.1 |
| f | 239.2 | 162.1 |
| l | 157.1 | 80 |
| o | 137.1 | 0 |
When I request a travel distance matrix I should get
| | a | f | l | o |
| a | 0+-2 | 2287+-2 | 1443+-2 | 1243+-2 |
| f | 2284+-2 | 0+-2 | 1241+-2 | 1443+-2 |
| l | 1443+-2 | 1244+-2 | 0+-2 | 600+-2 |
| o | 1243+-2 | 1444+-2 | 600+-2 | 0+-2 |
| | a | f | l | o |
| a | 0 | 2383.7 | 1566.9 | 1366.8 |
| f | 2339.9 | 0 | 1198.1 | 1522.1 |
| l | 1618.3 | 1293.3 | 0 | 800.5 |
| o | 1418.2 | 1617.3 | 800.5 | 0 |
When I request a travel distance matrix I should get
| | a | f | l | o |
| a | 0 | 2287.2+-2 | 1443+-2 | 1243+-2 |
| | a | f | l | o |
| a | 0 | 2383.7 | 1566.9 | 1366.8 |
When I request a travel distance matrix I should get
| | a |
| a | 0 |
| f | 2284.5+-2 |
| l | 1443.1 |
| o | 1243 |
| | a |
| a | 0 |
| f | 2339.9 |
| l | 1618.3 |
| o | 1418.2 |
When I request a travel distance matrix I should get
| | a | f | l | o |
| a | 0 | 2287+-2 | 1443+-2 | 1243+-2 |
| o | 1243 | 1444+-2 | 600+-2 | 0+-2 |
| | a | f | l | o |
| a | 0 | 2383.7 | 1566.9 | 1366.8 |
| f | 2339.9 | 0 | 1198.1 | 1522.1 |
When I request a travel distance matrix I should get
| | a | o |
| a | 0+-2 | 1243+-2 |
| f | 2284+-2 | 1443+-2 |
| l | 1443+-2 | 600+-2 |
| o | 1243+-2 | 0+-2 |
| | a | o |
| a | 0 | 1366.8 |
| f | 2339.9 | 1522.1 |
| l | 1618.3 | 800.5 |
| o | 1418.2 | 0 |
Scenario: Testbot - Multi level routing: horizontal road
Given the node map
+5 -2
View File
@@ -12,23 +12,26 @@ namespace contractor
struct ContractorEdgeData
{
ContractorEdgeData()
: weight(0), duration(0), id(0), originalEdges(0), shortcut(0), forward(0), backward(0)
: weight(0), duration(0), distance(0), id(0), originalEdges(0), shortcut(0), forward(0),
backward(0)
{
}
ContractorEdgeData(EdgeWeight weight,
EdgeWeight duration,
EdgeDistance distance,
unsigned original_edges,
unsigned id,
bool shortcut,
bool forward,
bool backward)
: weight(weight), duration(duration), id(id),
: weight(weight), duration(duration), distance(distance), id(id),
originalEdges(std::min((1u << 29) - 1u, original_edges)), shortcut(shortcut),
forward(forward), backward(backward)
{
}
EdgeWeight weight;
EdgeWeight duration;
EdgeDistance distance;
unsigned id;
unsigned originalEdges : 29;
bool shortcut : 1;
@@ -41,6 +41,7 @@ ContractorGraph toContractorGraph(NodeID number_of_nodes, InputEdgeContainer inp
input_edge.target,
std::max(input_edge.data.weight, 1),
input_edge.data.duration,
input_edge.data.distance,
1,
input_edge.data.turn_id,
false,
@@ -51,6 +52,7 @@ ContractorGraph toContractorGraph(NodeID number_of_nodes, InputEdgeContainer inp
input_edge.source,
std::max(input_edge.data.weight, 1),
input_edge.data.duration,
input_edge.data.distance,
1,
input_edge.data.turn_id,
false,
@@ -82,6 +84,7 @@ ContractorGraph toContractorGraph(NodeID number_of_nodes, InputEdgeContainer inp
forward_edge.data.originalEdges = reverse_edge.data.originalEdges = 1;
forward_edge.data.weight = reverse_edge.data.weight = INVALID_EDGE_WEIGHT;
forward_edge.data.duration = reverse_edge.data.duration = MAXIMAL_EDGE_DURATION;
forward_edge.data.distance = reverse_edge.data.distance = MAXIMAL_EDGE_DISTANCE;
// remove parallel edges
while (i < edges.size() && edges[i].source == source && edges[i].target == target)
{
@@ -90,12 +93,16 @@ ContractorGraph toContractorGraph(NodeID number_of_nodes, InputEdgeContainer inp
forward_edge.data.weight = std::min(edges[i].data.weight, forward_edge.data.weight);
forward_edge.data.duration =
std::min(edges[i].data.duration, forward_edge.data.duration);
forward_edge.data.distance =
std::min(edges[i].data.distance, forward_edge.data.distance);
}
if (edges[i].data.backward)
{
reverse_edge.data.weight = std::min(edges[i].data.weight, reverse_edge.data.weight);
reverse_edge.data.duration =
std::min(edges[i].data.duration, reverse_edge.data.duration);
reverse_edge.data.distance =
std::min(edges[i].data.distance, reverse_edge.data.distance);
}
++i;
}
@@ -151,6 +158,7 @@ template <class Edge, typename GraphT> inline std::vector<Edge> toEdges(GraphT g
BOOST_ASSERT_MSG(SPECIAL_NODEID != new_edge.target, "Target id invalid");
new_edge.data.weight = data.weight;
new_edge.data.duration = data.duration;
new_edge.data.distance = data.distance;
new_edge.data.shortcut = data.shortcut;
new_edge.data.turn_id = data.id;
BOOST_ASSERT_MSG(new_edge.data.turn_id != INT_MAX, // 2^31
+8 -3
View File
@@ -17,7 +17,8 @@ struct QueryEdge
struct EdgeData
{
explicit EdgeData()
: turn_id(0), shortcut(false), weight(0), duration(0), forward(false), backward(false)
: turn_id(0), shortcut(false), weight(0), duration(0), forward(false), backward(false),
distance(0)
{
}
@@ -25,10 +26,11 @@ struct QueryEdge
const bool shortcut,
const EdgeWeight weight,
const EdgeWeight duration,
const EdgeDistance distance,
const bool forward,
const bool backward)
: turn_id(turn_id), shortcut(shortcut), weight(weight), duration(duration),
forward(forward), backward(backward)
forward(forward), backward(backward), distance(distance)
{
}
@@ -40,6 +42,7 @@ struct QueryEdge
turn_id = other.id;
forward = other.forward;
backward = other.backward;
distance = other.distance;
}
// this ID is either the middle node of the shortcut, or the ID of the edge based node (node
// based edge) storing the appropriate data. If `shortcut` is set to true, we get the middle
@@ -50,6 +53,7 @@ struct QueryEdge
EdgeWeight duration : 30;
std::uint32_t forward : 1;
std::uint32_t backward : 1;
EdgeDistance distance;
} data;
QueryEdge() : source(SPECIAL_NODEID), target(SPECIAL_NODEID) {}
@@ -69,7 +73,8 @@ struct QueryEdge
return (source == right.source && target == right.target &&
data.weight == right.data.weight && data.duration == right.data.duration &&
data.shortcut == right.data.shortcut && data.forward == right.data.forward &&
data.backward == right.data.backward && data.turn_id == right.data.turn_id);
data.backward == right.data.backward && data.turn_id == right.data.turn_id &&
data.distance == right.data.distance);
}
};
}
+37 -11
View File
@@ -22,6 +22,7 @@ class CellCustomizer
{
bool from_clique;
EdgeDuration duration;
EdgeDistance distance;
};
public:
@@ -60,7 +61,7 @@ class CellCustomizer
}
}
heap.Clear();
heap.Insert(source, 0, {false, 0});
heap.Insert(source, 0, {false, 0, 0});
// explore search space
while (!heap.Empty() && !destinations_set.empty())
@@ -68,8 +69,18 @@ class CellCustomizer
const NodeID node = heap.DeleteMin();
const EdgeWeight weight = heap.GetKey(node);
const EdgeDuration duration = heap.GetData(node).duration;
const EdgeDistance distance = heap.GetData(node).distance;
RelaxNode(graph, cells, allowed_nodes, metric, heap, level, node, weight, duration);
RelaxNode(graph,
cells,
allowed_nodes,
metric,
heap,
level,
node,
weight,
duration,
distance);
destinations_set.erase(node);
}
@@ -77,21 +88,27 @@ class CellCustomizer
// fill a map of destination nodes to placeholder pointers
auto weights = cell.GetOutWeight(source);
auto durations = cell.GetOutDuration(source);
auto distances = cell.GetOutDistance(source);
for (auto &destination : destinations)
{
BOOST_ASSERT(!weights.empty());
BOOST_ASSERT(!durations.empty());
BOOST_ASSERT(!distances.empty());
const bool inserted = heap.WasInserted(destination);
weights.front() = inserted ? heap.GetKey(destination) : INVALID_EDGE_WEIGHT;
durations.front() =
inserted ? heap.GetData(destination).duration : MAXIMAL_EDGE_DURATION;
distances.front() =
inserted ? heap.GetData(destination).distance : INVALID_EDGE_DISTANCE;
weights.advance_begin(1);
durations.advance_begin(1);
distances.advance_begin(1);
}
BOOST_ASSERT(weights.empty());
BOOST_ASSERT(durations.empty());
BOOST_ASSERT(distances.empty());
}
}
@@ -128,7 +145,8 @@ class CellCustomizer
LevelID level,
NodeID node,
EdgeWeight weight,
EdgeDuration duration) const
EdgeDuration duration,
EdgeDistance distance) const
{
auto first_level = level == 1;
BOOST_ASSERT(heap.WasInserted(node));
@@ -149,6 +167,7 @@ class CellCustomizer
auto subcell = cells.GetCell(metric, level - 1, subcell_id);
auto subcell_destination = subcell.GetDestinationNodes().begin();
auto subcell_duration = subcell.GetOutDuration(node).begin();
auto subcell_distance = subcell.GetOutDistance(node).begin();
for (auto subcell_weight : subcell.GetOutWeight(node))
{
if (subcell_weight != INVALID_EDGE_WEIGHT)
@@ -161,20 +180,24 @@ class CellCustomizer
const EdgeWeight to_weight = weight + subcell_weight;
const EdgeDuration to_duration = duration + *subcell_duration;
const EdgeDistance to_distance = distance + *subcell_distance;
if (!heap.WasInserted(to))
{
heap.Insert(to, to_weight, {true, to_duration});
heap.Insert(to, to_weight, {true, to_duration, to_distance});
}
else if (std::tie(to_weight, to_duration) <
std::tie(heap.GetKey(to), heap.GetData(to).duration))
else if (std::tie(to_weight, to_duration, to_distance) <
std::tie(heap.GetKey(to),
heap.GetData(to).duration,
heap.GetData(to).distance))
{
heap.DecreaseKey(to, to_weight);
heap.GetData(to) = {true, to_duration};
heap.GetData(to) = {true, to_duration, to_distance};
}
}
++subcell_destination;
++subcell_duration;
++subcell_distance;
}
}
}
@@ -195,15 +218,18 @@ class CellCustomizer
{
const EdgeWeight to_weight = weight + data.weight;
const EdgeDuration to_duration = duration + data.duration;
const EdgeDistance to_distance = distance + data.distance;
if (!heap.WasInserted(to))
{
heap.Insert(to, to_weight, {false, duration + data.duration});
heap.Insert(
to, to_weight, {false, duration + data.duration, distance + data.distance});
}
else if (std::tie(to_weight, to_duration) <
std::tie(heap.GetKey(to), heap.GetData(to).duration))
else if (std::tie(to_weight, to_duration, to_distance) <
std::tie(
heap.GetKey(to), heap.GetData(to).duration, heap.GetData(to).distance))
{
heap.DecreaseKey(to, to_weight);
heap.GetData(to) = {false, to_duration};
heap.GetData(to) = {false, to_duration, to_distance};
}
}
}
+1
View File
@@ -20,6 +20,7 @@ template <storage::Ownership Ownership> struct CellMetricImpl
Vector<EdgeWeight> weights;
Vector<EdgeDuration> durations;
Vector<EdgeDistance> distances;
};
}
+10 -3
View File
@@ -58,8 +58,10 @@ class MultiLevelGraph : public partitioner::MultiLevelGraph<EdgeDataT, Ownership
MultiLevelGraph(PartitionerGraphT &&graph,
Vector<EdgeWeight> node_weights_,
Vector<EdgeDuration> node_durations_)
: node_weights(std::move(node_weights_)), node_durations(std::move(node_durations_))
Vector<EdgeDuration> node_durations_,
Vector<EdgeDistance> node_distances_)
: node_weights(std::move(node_weights_)), node_durations(std::move(node_durations_)),
node_distances(std::move(node_distances_))
{
util::ViewOrVector<PartitionerGraphT::EdgeArrayEntry, storage::Ownership::Container>
original_edge_array;
@@ -83,11 +85,13 @@ class MultiLevelGraph : public partitioner::MultiLevelGraph<EdgeDataT, Ownership
Vector<EdgeOffset> node_to_edge_offset_,
Vector<EdgeWeight> node_weights_,
Vector<EdgeDuration> node_durations_,
Vector<EdgeDistance> node_distances_,
Vector<bool> is_forward_edge_,
Vector<bool> is_backward_edge_)
: SuperT(std::move(node_array_), std::move(edge_array_), std::move(node_to_edge_offset_)),
node_weights(std::move(node_weights_)), node_durations(std::move(node_durations_)),
is_forward_edge(is_forward_edge_), is_backward_edge(is_backward_edge_)
node_distances(std::move(node_distances_)), is_forward_edge(is_forward_edge_),
is_backward_edge(is_backward_edge_)
{
}
@@ -95,6 +99,8 @@ class MultiLevelGraph : public partitioner::MultiLevelGraph<EdgeDataT, Ownership
EdgeWeight GetNodeDuration(NodeID node) const { return node_durations[node]; }
EdgeDistance GetNodeDistance(NodeID node) const { return node_distances[node]; }
bool IsForwardEdge(EdgeID edge) const { return is_forward_edge[edge]; }
bool IsBackwardEdge(EdgeID edge) const { return is_backward_edge[edge]; }
@@ -111,6 +117,7 @@ class MultiLevelGraph : public partitioner::MultiLevelGraph<EdgeDataT, Ownership
protected:
Vector<EdgeWeight> node_weights;
Vector<EdgeDuration> node_durations;
Vector<EdgeDistance> node_distances;
Vector<bool> is_forward_edge;
Vector<bool> is_backward_edge;
};
+4
View File
@@ -23,6 +23,7 @@ inline void read(storage::tar::FileReader &reader,
{
storage::serialization::read(reader, name + "/weights", metric.weights);
storage::serialization::read(reader, name + "/durations", metric.durations);
storage::serialization::read(reader, name + "/distances", metric.distances);
}
template <storage::Ownership Ownership>
@@ -32,6 +33,7 @@ inline void write(storage::tar::FileWriter &writer,
{
storage::serialization::write(writer, name + "/weights", metric.weights);
storage::serialization::write(writer, name + "/durations", metric.durations);
storage::serialization::write(writer, name + "/distances", metric.distances);
}
template <typename EdgeDataT, storage::Ownership Ownership>
@@ -42,6 +44,7 @@ inline void read(storage::tar::FileReader &reader,
storage::serialization::read(reader, name + "/node_array", graph.node_array);
storage::serialization::read(reader, name + "/node_weights", graph.node_weights);
storage::serialization::read(reader, name + "/node_durations", graph.node_durations);
storage::serialization::read(reader, name + "/node_distances", graph.node_distances);
storage::serialization::read(reader, name + "/edge_array", graph.edge_array);
storage::serialization::read(reader, name + "/is_forward_edge", graph.is_forward_edge);
storage::serialization::read(reader, name + "/is_backward_edge", graph.is_backward_edge);
@@ -56,6 +59,7 @@ inline void write(storage::tar::FileWriter &writer,
storage::serialization::write(writer, name + "/node_array", graph.node_array);
storage::serialization::write(writer, name + "/node_weights", graph.node_weights);
storage::serialization::write(writer, name + "/node_durations", graph.node_durations);
storage::serialization::write(writer, name + "/node_distances", graph.node_distances);
storage::serialization::write(writer, name + "/edge_array", graph.edge_array);
storage::serialization::write(writer, name + "/is_forward_edge", graph.is_forward_edge);
storage::serialization::write(writer, name + "/is_backward_edge", graph.is_backward_edge);
+26 -8
View File
@@ -59,6 +59,15 @@ struct TableParameters : public BaseParameters
{
std::vector<std::size_t> sources;
std::vector<std::size_t> destinations;
double fallback_speed = 0;
enum class FallbackCoordinateType
{
Input = 0,
Snapped = 1
};
FallbackCoordinateType fallback_coordinate_type = FallbackCoordinateType::Input;
enum class AnnotationsType
{
@@ -90,6 +99,19 @@ struct TableParameters : public BaseParameters
{
}
template <typename... Args>
TableParameters(std::vector<std::size_t> sources_,
std::vector<std::size_t> destinations_,
const AnnotationsType annotations_,
double fallback_speed_,
FallbackCoordinateType fallback_coordinate_type_,
Args... args_)
: BaseParameters{std::forward<Args>(args_)...}, sources{std::move(sources_)},
destinations{std::move(destinations_)}, fallback_speed{fallback_speed_},
fallback_coordinate_type{fallback_coordinate_type_}, annotations{annotations_}
{
}
bool IsValid() const
{
if (!BaseParameters::IsValid())
@@ -101,14 +123,7 @@ struct TableParameters : public BaseParameters
// 1/ The user is able to specify duplicates in srcs and dsts, in that case it's their fault
// 2/ len(srcs) and len(dsts) smaller or equal to len(locations)
if (sources.size() > coordinates.size())
return false;
if (destinations.size() > coordinates.size())
return false;
// 3/ 0 <= index < len(locations)
// 2/ 0 <= index < len(locations)
const auto not_in_range = [this](const std::size_t x) { return x >= coordinates.size(); };
if (std::any_of(begin(sources), end(sources), not_in_range))
@@ -117,6 +132,9 @@ struct TableParameters : public BaseParameters
if (std::any_of(begin(destinations), end(destinations), not_in_range))
return false;
if (fallback_speed < 0)
return false;
return true;
}
};
@@ -78,6 +78,8 @@ template <> class AlgorithmDataFacade<MLD>
virtual EdgeWeight GetNodeDuration(const NodeID node) const = 0; // TODO: to be removed
virtual EdgeDistance GetNodeDistance(const NodeID node) const = 0;
virtual bool IsForwardEdge(EdgeID edge) const = 0;
virtual bool IsBackwardEdge(EdgeID edge) const = 0;
@@ -697,6 +697,11 @@ template <> class ContiguousInternalMemoryAlgorithmDataFacade<MLD> : public Algo
return query_graph.GetNodeDuration(node);
}
EdgeDistance GetNodeDistance(const NodeID node) const override final
{
return query_graph.GetNodeDistance(node);
}
bool IsForwardEdge(const NodeID node) const override final
{
return query_graph.IsForwardEdge(node);
@@ -10,6 +10,7 @@
#include <boost/iostreams/device/mapped_file.hpp>
#include <memory>
#include <string>
namespace osrm
{
@@ -24,8 +25,7 @@ namespace datafacade
class MMapMemoryAllocator : public ContiguousBlockAllocator
{
public:
explicit MMapMemoryAllocator(const storage::StorageConfig &config,
const boost::filesystem::path &memory_file);
explicit MMapMemoryAllocator(const storage::StorageConfig &config);
~MMapMemoryAllocator() override final;
// interface to give access to the datafacades
@@ -33,8 +33,8 @@ class MMapMemoryAllocator : public ContiguousBlockAllocator
private:
storage::SharedDataIndex index;
util::vector_view<char> mapped_memory;
boost::iostreams::mapped_file mapped_memory_file;
std::vector<boost::iostreams::mapped_file> mapped_memory_files;
std::string rtree_filename;
};
} // namespace datafacade
+2 -3
View File
@@ -32,9 +32,8 @@ class ExternalProvider final : public DataFacadeProvider<AlgorithmT, FacadeT>
public:
using Facade = typename DataFacadeProvider<AlgorithmT, FacadeT>::Facade;
ExternalProvider(const storage::StorageConfig &config,
const boost::filesystem::path &memory_file)
: facade_factory(std::make_shared<datafacade::MMapMemoryAllocator>(config, memory_file))
ExternalProvider(const storage::StorageConfig &config)
: facade_factory(std::make_shared<datafacade::MMapMemoryAllocator>(config))
{
}
+9 -5
View File
@@ -63,12 +63,16 @@ template <typename Algorithm> class Engine final : public EngineInterface
<< "\" with algorithm " << routing_algorithms::name<Algorithm>();
facade_provider = std::make_unique<WatchingProvider<Algorithm>>(config.dataset_name);
}
else if (!config.memory_file.empty())
else if (!config.memory_file.empty() || config.use_mmap)
{
util::Log(logDEBUG) << "Using memory mapped filed at " << config.memory_file
<< " with algorithm " << routing_algorithms::name<Algorithm>();
facade_provider = std::make_unique<ExternalProvider<Algorithm>>(config.storage_config,
config.memory_file);
if (!config.memory_file.empty())
{
util::Log(logWARNING)
<< "The 'memory_file' option is DEPRECATED - using direct mmaping instead";
}
util::Log(logDEBUG) << "Using direct memory mapping with algorithm "
<< routing_algorithms::name<Algorithm>();
facade_provider = std::make_unique<ExternalProvider<Algorithm>>(config.storage_config);
}
else
{
+1
View File
@@ -89,6 +89,7 @@ struct EngineConfig final
int max_alternatives = 3; // set an arbitrary upper bound; can be adjusted by user
bool use_shared_memory = true;
boost::filesystem::path memory_file;
bool use_mmap = true;
Algorithm algorithm = Algorithm::CH;
std::string verbosity;
std::string dataset_name;
+14 -13
View File
@@ -449,7 +449,6 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
const auto reverse_durations = datafacade.GetUncompressedReverseDurations(geometry_id);
const auto forward_geometry = datafacade.GetUncompressedForwardGeometry(geometry_id);
const auto reverse_geometry = datafacade.GetUncompressedReverseGeometry(geometry_id);
const auto forward_weight_offset =
std::accumulate(forward_weights.begin(),
@@ -480,19 +479,19 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
datafacade.GetCoordinateOfNode(forward_geometry(data.fwd_segment_position)),
point_on_segment);
const auto rev_segment_position = reverse_weights.size() - data.fwd_segment_position - 1;
const auto reverse_weight_offset = std::accumulate(
reverse_weights.begin(), reverse_weights.begin() + rev_segment_position, EdgeWeight{0});
const auto reverse_weight_offset =
std::accumulate(reverse_weights.begin(),
reverse_weights.end() - data.fwd_segment_position - 1,
EdgeWeight{0});
const auto reverse_duration_offset =
std::accumulate(reverse_durations.begin(),
reverse_durations.begin() + rev_segment_position,
reverse_durations.end() - data.fwd_segment_position - 1,
EdgeDuration{0});
EdgeDistance reverse_distance_offset = 0;
for (auto current = reverse_geometry.begin();
current < reverse_geometry.begin() + rev_segment_position;
for (auto current = forward_geometry.begin();
current < forward_geometry.end() - data.fwd_segment_position - 2;
++current)
{
reverse_distance_offset += util::coordinate_calculation::fccApproximateDistance(
@@ -500,11 +499,13 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
datafacade.GetCoordinateOfNode(*std::next(current)));
}
EdgeWeight reverse_weight = reverse_weights[rev_segment_position];
EdgeDuration reverse_duration = reverse_durations[rev_segment_position];
EdgeWeight reverse_weight =
reverse_weights[reverse_weights.size() - data.fwd_segment_position - 1];
EdgeDuration reverse_duration =
reverse_durations[reverse_durations.size() - data.fwd_segment_position - 1];
EdgeDistance reverse_distance = util::coordinate_calculation::fccApproximateDistance(
point_on_segment,
datafacade.GetCoordinateOfNode(reverse_geometry(rev_segment_position)));
datafacade.GetCoordinateOfNode(forward_geometry(data.fwd_segment_position + 1)));
ratio = std::min(1.0, std::max(0.0, ratio));
if (data.forward_segment_id.id != SPECIAL_SEGMENTID)
@@ -692,7 +693,7 @@ template <typename RTreeT, typename DataFacadeT> class GeospatialQuery
const CoordinateList &coordinates;
DataFacadeT &datafacade;
};
} // namespace engine
} // namespace osrm
}
}
#endif
+4 -8
View File
@@ -34,8 +34,7 @@ class RoutingAlgorithmsInterface
ManyToManySearch(const std::vector<PhantomNode> &phantom_nodes,
const std::vector<std::size_t> &source_indices,
const std::vector<std::size_t> &target_indices,
const bool calculate_distance,
const bool calculate_duration) const = 0;
const bool calculate_distance) const = 0;
virtual routing_algorithms::SubMatchingList
MapMatching(const routing_algorithms::CandidateLists &candidates_list,
@@ -88,8 +87,7 @@ template <typename Algorithm> class RoutingAlgorithms final : public RoutingAlgo
ManyToManySearch(const std::vector<PhantomNode> &phantom_nodes,
const std::vector<std::size_t> &source_indices,
const std::vector<std::size_t> &target_indices,
const bool calculate_distance,
const bool calculate_duration) const final override;
const bool calculate_distance) const final override;
routing_algorithms::SubMatchingList
MapMatching(const routing_algorithms::CandidateLists &candidates_list,
@@ -198,8 +196,7 @@ std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
RoutingAlgorithms<Algorithm>::ManyToManySearch(const std::vector<PhantomNode> &phantom_nodes,
const std::vector<std::size_t> &_source_indices,
const std::vector<std::size_t> &_target_indices,
const bool calculate_distance,
const bool calculate_duration) const
const bool calculate_distance) const
{
BOOST_ASSERT(!phantom_nodes.empty());
@@ -222,8 +219,7 @@ RoutingAlgorithms<Algorithm>::ManyToManySearch(const std::vector<PhantomNode> &p
phantom_nodes,
std::move(source_indices),
std::move(target_indices),
calculate_distance,
calculate_duration);
calculate_distance);
}
template <typename Algorithm>
@@ -25,15 +25,17 @@ struct NodeBucket
unsigned from_clique_arc : 1;
EdgeWeight weight;
EdgeDuration duration;
EdgeDistance distance;
NodeBucket(NodeID middle_node,
NodeID parent_node,
bool from_clique_arc,
unsigned column_index,
EdgeWeight weight,
EdgeDuration duration)
EdgeDuration duration,
EdgeDistance distance)
: middle_node(middle_node), parent_node(parent_node), column_index(column_index),
from_clique_arc(from_clique_arc), weight(weight), duration(duration)
from_clique_arc(from_clique_arc), weight(weight), duration(duration), distance(distance)
{
}
@@ -41,9 +43,10 @@ struct NodeBucket
NodeID parent_node,
unsigned column_index,
EdgeWeight weight,
EdgeDuration duration)
EdgeDuration duration,
EdgeDistance distance)
: middle_node(middle_node), parent_node(parent_node), column_index(column_index),
from_clique_arc(false), weight(weight), duration(duration)
from_clique_arc(false), weight(weight), duration(duration), distance(distance)
{
}
@@ -94,8 +97,7 @@ manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
const std::vector<PhantomNode> &phantom_nodes,
const std::vector<std::size_t> &source_indices,
const std::vector<std::size_t> &target_indices,
const bool calculate_distance,
const bool calculate_duration);
const bool calculate_distance);
} // namespace routing_algorithms
} // namespace engine
+110 -127
View File
@@ -44,144 +44,79 @@ bool needsLoopBackwards(const PhantomNode &source_phantom, const PhantomNode &ta
bool needsLoopForward(const PhantomNodes &phantoms);
bool needsLoopBackwards(const PhantomNodes &phantoms);
namespace detail
{
template <typename Algorithm>
void insertSourceInHeap(typename SearchEngineData<Algorithm>::ManyToManyQueryHeap &heap,
const PhantomNode &phantom_node)
{
if (phantom_node.IsValidForwardTarget())
{
heap.Insert(phantom_node.forward_segment_id.id,
-phantom_node.GetForwardWeightPlusOffset(),
{phantom_node.forward_segment_id.id, -phantom_node.GetForwardDuration()});
}
if (phantom_node.IsValidReverseTarget())
{
heap.Insert(phantom_node.reverse_segment_id.id,
-phantom_node.GetReverseWeightPlusOffset(),
{phantom_node.reverse_segment_id.id, -phantom_node.GetReverseDuration()});
}
}
template <typename Algorithm>
void insertTargetInHeap(typename SearchEngineData<Algorithm>::ManyToManyQueryHeap &heap,
const PhantomNode &phantom_node)
{
if (phantom_node.IsValidForwardTarget())
{
heap.Insert(phantom_node.forward_segment_id.id,
phantom_node.GetForwardWeightPlusOffset(),
{phantom_node.forward_segment_id.id, phantom_node.GetForwardDuration()});
}
if (phantom_node.IsValidReverseTarget())
{
heap.Insert(phantom_node.reverse_segment_id.id,
phantom_node.GetReverseWeightPlusOffset(),
{phantom_node.reverse_segment_id.id, phantom_node.GetReverseDuration()});
}
}
template <typename Algorithm>
void insertSourceInHeap(typename SearchEngineData<Algorithm>::QueryHeap &heap,
const PhantomNode &phantom_node)
{
if (phantom_node.IsValidForwardSource())
{
heap.Insert(phantom_node.forward_segment_id.id,
-phantom_node.GetForwardWeightPlusOffset(),
phantom_node.forward_segment_id.id);
}
if (phantom_node.IsValidReverseSource())
{
heap.Insert(phantom_node.reverse_segment_id.id,
-phantom_node.GetReverseWeightPlusOffset(),
phantom_node.reverse_segment_id.id);
}
}
template <typename Algorithm>
void insertTargetInHeap(typename SearchEngineData<Algorithm>::QueryHeap &heap,
const PhantomNode &phantom_node)
{
if (phantom_node.IsValidForwardTarget())
{
heap.Insert(phantom_node.forward_segment_id.id,
phantom_node.GetForwardWeightPlusOffset(),
phantom_node.forward_segment_id.id);
}
if (phantom_node.IsValidReverseTarget())
{
heap.Insert(phantom_node.reverse_segment_id.id,
phantom_node.GetReverseWeightPlusOffset(),
phantom_node.reverse_segment_id.id);
}
}
} // namespace detail
inline void insertTargetInHeap(typename SearchEngineData<mld::Algorithm>::ManyToManyQueryHeap &heap,
const PhantomNode &phantom_node)
{
detail::insertTargetInHeap<mld::Algorithm>(heap, phantom_node);
}
inline void insertTargetInHeap(typename SearchEngineData<ch::Algorithm>::ManyToManyQueryHeap &heap,
const PhantomNode &phantom_node)
{
detail::insertTargetInHeap<ch::Algorithm>(heap, phantom_node);
}
inline void insertTargetInHeap(typename SearchEngineData<mld::Algorithm>::QueryHeap &heap,
const PhantomNode &phantom_node)
{
detail::insertTargetInHeap<mld::Algorithm>(heap, phantom_node);
}
inline void insertTargetInHeap(typename SearchEngineData<ch::Algorithm>::QueryHeap &heap,
const PhantomNode &phantom_node)
{
detail::insertTargetInHeap<ch::Algorithm>(heap, phantom_node);
}
inline void insertSourceInHeap(typename SearchEngineData<mld::Algorithm>::ManyToManyQueryHeap &heap,
const PhantomNode &phantom_node)
{
detail::insertSourceInHeap<mld::Algorithm>(heap, phantom_node);
}
inline void insertSourceInHeap(typename SearchEngineData<ch::Algorithm>::ManyToManyQueryHeap &heap,
const PhantomNode &phantom_node)
{
detail::insertSourceInHeap<ch::Algorithm>(heap, phantom_node);
}
inline void insertSourceInHeap(typename SearchEngineData<mld::Algorithm>::QueryHeap &heap,
const PhantomNode &phantom_node)
{
detail::insertSourceInHeap<mld::Algorithm>(heap, phantom_node);
}
inline void insertSourceInHeap(typename SearchEngineData<ch::Algorithm>::QueryHeap &heap,
const PhantomNode &phantom_node)
{
detail::insertSourceInHeap<ch::Algorithm>(heap, phantom_node);
}
template <typename Heap>
void insertNodesInHeaps(Heap &forward_heap, Heap &reverse_heap, const PhantomNodes &nodes)
{
insertSourceInHeap(forward_heap, nodes.source_phantom);
insertTargetInHeap(reverse_heap, nodes.target_phantom);
const auto &source = nodes.source_phantom;
if (source.IsValidForwardSource())
{
forward_heap.Insert(source.forward_segment_id.id,
-source.GetForwardWeightPlusOffset(),
source.forward_segment_id.id);
}
if (source.IsValidReverseSource())
{
forward_heap.Insert(source.reverse_segment_id.id,
-source.GetReverseWeightPlusOffset(),
source.reverse_segment_id.id);
}
const auto &target = nodes.target_phantom;
if (target.IsValidForwardTarget())
{
reverse_heap.Insert(target.forward_segment_id.id,
target.GetForwardWeightPlusOffset(),
target.forward_segment_id.id);
}
if (target.IsValidReverseTarget())
{
reverse_heap.Insert(target.reverse_segment_id.id,
target.GetReverseWeightPlusOffset(),
target.reverse_segment_id.id);
}
}
template <typename Algorithm>
void insertSourceInHeap(typename SearchEngineData<Algorithm>::ManyToManyQueryHeap &heap,
const PhantomNode &phantom_node)
template <typename ManyToManyQueryHeap>
void insertSourceInHeap(ManyToManyQueryHeap &heap, const PhantomNode &phantom_node)
{
if (phantom_node.IsValidForwardSource())
{
heap.Insert(phantom_node.forward_segment_id.id,
-phantom_node.GetForwardWeightPlusOffset(),
{phantom_node.forward_segment_id.id, -phantom_node.GetForwardDuration()});
{phantom_node.forward_segment_id.id,
-phantom_node.GetForwardDuration(),
-phantom_node.GetForwardDistance()});
}
if (phantom_node.IsValidReverseSource())
{
heap.Insert(phantom_node.reverse_segment_id.id,
-phantom_node.GetReverseWeightPlusOffset(),
{phantom_node.reverse_segment_id.id, -phantom_node.GetReverseDuration()});
{phantom_node.reverse_segment_id.id,
-phantom_node.GetReverseDuration(),
-phantom_node.GetReverseDistance()});
}
}
template <typename ManyToManyQueryHeap>
void insertTargetInHeap(ManyToManyQueryHeap &heap, const PhantomNode &phantom_node)
{
if (phantom_node.IsValidForwardTarget())
{
heap.Insert(phantom_node.forward_segment_id.id,
phantom_node.GetForwardWeightPlusOffset(),
{phantom_node.forward_segment_id.id,
phantom_node.GetForwardDuration(),
phantom_node.GetForwardDistance()});
}
if (phantom_node.IsValidReverseTarget())
{
heap.Insert(phantom_node.reverse_segment_id.id,
phantom_node.GetReverseWeightPlusOffset(),
{phantom_node.reverse_segment_id.id,
phantom_node.GetReverseDuration(),
phantom_node.GetReverseDistance()});
}
}
@@ -394,10 +329,58 @@ void annotatePath(const FacadeT &facade,
}
}
EdgeDistance adjustPathDistanceToPhantomNodes(const std::vector<NodeID> &path,
const PhantomNode &source_phantom,
const PhantomNode &target_phantom,
const EdgeDistance distance);
template <typename Algorithm>
double getPathDistance(const DataFacade<Algorithm> &facade,
const std::vector<PathData> unpacked_path,
const PhantomNode &source_phantom,
const PhantomNode &target_phantom)
{
using util::coordinate_calculation::detail::DEGREE_TO_RAD;
using util::coordinate_calculation::detail::EARTH_RADIUS;
double distance = 0;
double prev_lat =
static_cast<double>(util::toFloating(source_phantom.location.lat)) * DEGREE_TO_RAD;
double prev_lon =
static_cast<double>(util::toFloating(source_phantom.location.lon)) * DEGREE_TO_RAD;
double prev_cos = std::cos(prev_lat);
for (const auto &p : unpacked_path)
{
const auto current_coordinate = facade.GetCoordinateOfNode(p.turn_via_node);
const double current_lat =
static_cast<double>(util::toFloating(current_coordinate.lat)) * DEGREE_TO_RAD;
const double current_lon =
static_cast<double>(util::toFloating(current_coordinate.lon)) * DEGREE_TO_RAD;
const double current_cos = std::cos(current_lat);
const double sin_dlon = std::sin((prev_lon - current_lon) / 2.0);
const double sin_dlat = std::sin((prev_lat - current_lat) / 2.0);
const double aharv = sin_dlat * sin_dlat + prev_cos * current_cos * sin_dlon * sin_dlon;
const double charv = 2. * std::atan2(std::sqrt(aharv), std::sqrt(1.0 - aharv));
distance += EARTH_RADIUS * charv;
prev_lat = current_lat;
prev_lon = current_lon;
prev_cos = current_cos;
}
const double current_lat =
static_cast<double>(util::toFloating(target_phantom.location.lat)) * DEGREE_TO_RAD;
const double current_lon =
static_cast<double>(util::toFloating(target_phantom.location.lon)) * DEGREE_TO_RAD;
const double current_cos = std::cos(current_lat);
const double sin_dlon = std::sin((prev_lon - current_lon) / 2.0);
const double sin_dlat = std::sin((prev_lat - current_lat) / 2.0);
const double aharv = sin_dlat * sin_dlat + prev_cos * current_cos * sin_dlon * sin_dlon;
const double charv = 2. * std::atan2(std::sqrt(aharv), std::sqrt(1.0 - aharv));
distance += EARTH_RADIUS * charv;
return distance;
}
template <typename AlgorithmT>
InternalRouteResult extractRoute(const DataFacade<AlgorithmT> &facade,
@@ -186,9 +186,10 @@ void routingStep(const DataFacade<Algorithm> &facade,
}
template <bool UseDuration>
EdgeWeight getLoopWeight(const DataFacade<Algorithm> &facade, NodeID node)
std::tuple<EdgeWeight, EdgeDistance> getLoopWeight(const DataFacade<Algorithm> &facade, NodeID node)
{
EdgeWeight loop_weight = UseDuration ? MAXIMAL_EDGE_DURATION : INVALID_EDGE_WEIGHT;
EdgeDistance loop_distance = MAXIMAL_EDGE_DISTANCE;
for (auto edge : facade.GetAdjacentEdgeRange(node))
{
const auto &data = facade.GetEdgeData(edge);
@@ -198,11 +199,15 @@ EdgeWeight getLoopWeight(const DataFacade<Algorithm> &facade, NodeID node)
if (to == node)
{
const auto value = UseDuration ? data.duration : data.weight;
loop_weight = std::min(loop_weight, value);
if (value < loop_weight)
{
loop_weight = value;
loop_distance = data.distance;
}
}
}
}
return loop_weight;
return std::make_tuple(loop_weight, loop_distance);
}
/**
@@ -97,6 +97,7 @@ inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
const std::vector<std::size_t> &phantom_indices)
{
auto min_level = [&partition, node](const PhantomNode &phantom_node) {
const auto &forward_segment = phantom_node.forward_segment_id;
const auto forward_level =
forward_segment.enabled ? partition.GetHighestDifferentLevel(node, forward_segment.id)
@@ -119,7 +120,7 @@ inline LevelID getNodeQueryLevel(const MultiLevelPartition &partition,
}
return result;
}
} // namespace
}
// Heaps only record for each node its predecessor ("parent") on the shortest path.
// For re-constructing the actual path we need to trace back all parent "pointers".
@@ -390,27 +391,21 @@ UnpackedPath search(SearchEngineData<Algorithm> &engine_working_data,
EdgeWeight weight_upper_bound,
Args... args)
{
if (forward_heap.Empty() && reverse_heap.Empty())
if (forward_heap.Empty() || reverse_heap.Empty())
{
return std::make_tuple(INVALID_EDGE_WEIGHT, std::vector<NodeID>(), std::vector<EdgeID>());
}
const auto &partition = facade.GetMultiLevelPartition();
BOOST_ASSERT(forward_heap.Empty() || forward_heap.MinKey() < INVALID_EDGE_WEIGHT);
BOOST_ASSERT(reverse_heap.Empty() || reverse_heap.MinKey() < INVALID_EDGE_WEIGHT);
BOOST_ASSERT(!forward_heap.Empty() && forward_heap.MinKey() < INVALID_EDGE_WEIGHT);
BOOST_ASSERT(!reverse_heap.Empty() && reverse_heap.MinKey() < INVALID_EDGE_WEIGHT);
// run two-Target Dijkstra routing step.
NodeID middle = SPECIAL_NODEID;
EdgeWeight weight = weight_upper_bound;
EdgeWeight forward_heap_min = 0;
if (!forward_heap.Empty())
forward_heap_min = forward_heap.MinKey();
EdgeWeight reverse_heap_min = 0;
if (!reverse_heap.Empty())
reverse_heap_min = reverse_heap.MinKey();
EdgeWeight forward_heap_min = forward_heap.MinKey();
EdgeWeight reverse_heap_min = reverse_heap.MinKey();
while (forward_heap.Size() + reverse_heap.Size() > 0 &&
forward_heap_min + reverse_heap_min < weight)
{
@@ -514,90 +509,6 @@ UnpackedPath search(SearchEngineData<Algorithm> &engine_working_data,
return std::make_tuple(weight, std::move(unpacked_nodes), std::move(unpacked_edges));
}
// With (s, middle, t) we trace back the paths middle -> s and middle -> t.
// This gives us a packed path (node ids) from the base graph around s and t,
// and overlay node ids otherwise. We then have to unpack the overlay clique
// edges by recursively descending unpacking the path down to the base graph.
using UnpackedNodes = std::vector<NodeID>;
using UnpackedEdges = std::vector<EdgeID>;
using UnpackedPath = std::tuple<EdgeWeight, UnpackedNodes, UnpackedEdges>;
template <typename Algorithm, typename... Args>
UnpackedPath
unpackPathAndCalculateDistance(SearchEngineData<Algorithm> &engine_working_data,
const DataFacade<Algorithm> &facade,
typename SearchEngineData<Algorithm>::QueryHeap &forward_heap,
typename SearchEngineData<Algorithm>::QueryHeap &reverse_heap,
const bool force_loop_forward,
const bool force_loop_reverse,
EdgeWeight weight_upper_bound,
PackedPath packed_path,
NodeID middle,
Args... args)
{
EdgeWeight weight = weight_upper_bound;
const auto &partition = facade.GetMultiLevelPartition();
const NodeID source_node = !packed_path.empty() ? std::get<0>(packed_path.front()) : middle;
// Unpack path
std::vector<NodeID> unpacked_nodes;
std::vector<EdgeID> unpacked_edges;
unpacked_nodes.reserve(packed_path.size());
unpacked_edges.reserve(packed_path.size());
unpacked_nodes.push_back(source_node);
for (auto const &packed_edge : packed_path)
{
NodeID source, target;
bool overlay_edge;
std::tie(source, target, overlay_edge) = packed_edge;
if (!overlay_edge)
{ // a base graph edge
unpacked_nodes.push_back(target);
unpacked_edges.push_back(facade.FindEdge(source, target));
}
else
{ // an overlay graph edge
LevelID level = getNodeQueryLevel(partition, source, args...);
CellID parent_cell_id = partition.GetCell(level, source);
BOOST_ASSERT(parent_cell_id == partition.GetCell(level, target));
LevelID sublevel = level - 1;
// Here heaps can be reused, let's go deeper!
forward_heap.Clear();
reverse_heap.Clear();
forward_heap.Insert(source, 0, {source});
reverse_heap.Insert(target, 0, {target});
// TODO: when structured bindings will be allowed change to
// auto [subpath_weight, subpath_source, subpath_target, subpath] = ...
EdgeWeight subpath_weight;
std::vector<NodeID> subpath_nodes;
std::vector<EdgeID> subpath_edges;
std::tie(subpath_weight, subpath_nodes, subpath_edges) = search(engine_working_data,
facade,
forward_heap,
reverse_heap,
force_loop_forward,
force_loop_reverse,
weight_upper_bound,
sublevel,
parent_cell_id);
BOOST_ASSERT(!subpath_edges.empty());
BOOST_ASSERT(subpath_nodes.size() > 1);
BOOST_ASSERT(subpath_nodes.front() == source);
BOOST_ASSERT(subpath_nodes.back() == target);
unpacked_nodes.insert(
unpacked_nodes.end(), std::next(subpath_nodes.begin()), subpath_nodes.end());
unpacked_edges.insert(unpacked_edges.end(), subpath_edges.begin(), subpath_edges.end());
}
}
return std::make_tuple(weight, std::move(unpacked_nodes), std::move(unpacked_edges));
}
// Alias to be compatible with the CH-based search
template <typename Algorithm>
inline void search(SearchEngineData<Algorithm> &engine_working_data,
@@ -662,7 +573,11 @@ double getNetworkDistance(SearchEngineData<Algorithm> &engine_working_data,
const PhantomNode &target_phantom,
EdgeWeight weight_upper_bound = INVALID_EDGE_WEIGHT)
{
forward_heap.Clear();
reverse_heap.Clear();
const PhantomNodes phantom_nodes{source_phantom, target_phantom};
insertNodesInHeaps(forward_heap, reverse_heap, phantom_nodes);
EdgeWeight weight = INVALID_EDGE_WEIGHT;
std::vector<NodeID> unpacked_nodes;
@@ -681,22 +596,11 @@ double getNetworkDistance(SearchEngineData<Algorithm> &engine_working_data,
return std::numeric_limits<double>::max();
}
EdgeDistance distance = 0;
std::vector<PathData> unpacked_path;
if (!unpacked_nodes.empty())
{
distance = std::accumulate(unpacked_nodes.begin(),
std::prev(unpacked_nodes.end()),
EdgeDistance{0},
[&](const EdgeDistance distance, const auto node_id) {
return distance + computeEdgeDistance(facade, node_id);
});
}
annotatePath(facade, phantom_nodes, unpacked_nodes, unpacked_edges, unpacked_path);
distance = adjustPathDistanceToPhantomNodes(
unpacked_nodes, phantom_nodes.source_phantom, phantom_nodes.target_phantom, distance);
return distance;
return getPathDistance(facade, unpacked_path, source_phantom, target_phantom);
}
} // namespace mld
+13 -5
View File
@@ -30,7 +30,11 @@ struct HeapData
struct ManyToManyHeapData : HeapData
{
EdgeWeight duration;
ManyToManyHeapData(NodeID p, EdgeWeight duration) : HeapData(p), duration(duration) {}
EdgeDistance distance;
ManyToManyHeapData(NodeID p, EdgeWeight duration, EdgeDistance distance)
: HeapData(p), duration(duration), distance(distance)
{
}
};
template <> struct SearchEngineData<routing_algorithms::ch::Algorithm>
@@ -75,12 +79,16 @@ struct MultiLayerDijkstraHeapData
struct ManyToManyMultiLayerDijkstraHeapData : MultiLayerDijkstraHeapData
{
EdgeWeight duration;
ManyToManyMultiLayerDijkstraHeapData(NodeID p, EdgeWeight duration)
: MultiLayerDijkstraHeapData(p), duration(duration)
EdgeDistance distance;
ManyToManyMultiLayerDijkstraHeapData(NodeID p, EdgeWeight duration, EdgeDistance distance)
: MultiLayerDijkstraHeapData(p), duration(duration), distance(distance)
{
}
ManyToManyMultiLayerDijkstraHeapData(NodeID p, bool from, EdgeWeight duration)
: MultiLayerDijkstraHeapData(p, from), duration(duration)
ManyToManyMultiLayerDijkstraHeapData(NodeID p,
bool from,
EdgeWeight duration,
EdgeDistance distance)
: MultiLayerDijkstraHeapData(p, from), duration(duration), distance(distance)
{
}
};
+12 -5
View File
@@ -15,20 +15,25 @@ struct EdgeBasedEdge
public:
struct EdgeData
{
EdgeData() : turn_id(0), weight(0), duration(0), forward(false), backward(false) {}
EdgeData()
: turn_id(0), weight(0), distance(0), duration(0), forward(false), backward(false)
{
}
EdgeData(const NodeID turn_id,
const EdgeWeight weight,
const EdgeDistance distance,
const EdgeWeight duration,
const bool forward,
const bool backward)
: turn_id(turn_id), weight(weight), duration(duration), forward(forward),
backward(backward)
: turn_id(turn_id), weight(weight), distance(distance), duration(duration),
forward(forward), backward(backward)
{
}
NodeID turn_id; // ID of the edge based node (node based edge)
EdgeWeight weight;
EdgeDistance distance;
EdgeWeight duration : 30;
std::uint32_t forward : 1;
std::uint32_t backward : 1;
@@ -43,6 +48,7 @@ struct EdgeBasedEdge
const NodeID edge_id,
const EdgeWeight weight,
const EdgeWeight duration,
const EdgeDistance distance,
const bool forward,
const bool backward);
EdgeBasedEdge(const NodeID source, const NodeID target, const EdgeBasedEdge::EdgeData &data);
@@ -53,7 +59,7 @@ struct EdgeBasedEdge
NodeID target;
EdgeData data;
};
static_assert(sizeof(extractor::EdgeBasedEdge) == 20,
static_assert(sizeof(extractor::EdgeBasedEdge) == 24,
"Size of extractor::EdgeBasedEdge type is "
"bigger than expected. This will influence "
"memory consumption.");
@@ -67,9 +73,10 @@ inline EdgeBasedEdge::EdgeBasedEdge(const NodeID source,
const NodeID turn_id,
const EdgeWeight weight,
const EdgeWeight duration,
const EdgeDistance distance,
const bool forward,
const bool backward)
: source(source), target(target), data{turn_id, weight, duration, forward, backward}
: source(source), target(target), data{turn_id, weight, distance, duration, forward, backward}
{
}
@@ -92,6 +92,7 @@ class EdgeBasedGraphFactory
void GetStartPointMarkers(std::vector<bool> &node_is_startpoint);
void GetEdgeBasedNodeWeights(std::vector<EdgeWeight> &output_node_weights);
void GetEdgeBasedNodeDurations(std::vector<EdgeWeight> &output_node_durations);
void GetEdgeBasedNodeDistances(std::vector<EdgeDistance> &output_node_distances);
std::uint32_t GetConnectivityChecksum() const;
std::uint64_t GetNumberOfEdgeBasedNodes() const;
@@ -119,6 +120,7 @@ class EdgeBasedGraphFactory
//! edge-based node
std::vector<EdgeWeight> m_edge_based_node_weights;
std::vector<EdgeDuration> m_edge_based_node_durations;
std::vector<EdgeDistance> m_edge_based_node_distances;
//! list of edge based nodes (compressed segments)
std::vector<EdgeBasedNodeSegment> m_edge_based_node_segments;
+1
View File
@@ -88,6 +88,7 @@ class Extractor
std::vector<bool> &node_is_startpoint,
std::vector<EdgeWeight> &edge_based_node_weights,
std::vector<EdgeDuration> &edge_based_node_durations,
std::vector<EdgeDistance> &edge_based_node_distances,
util::DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list,
std::uint32_t &connectivity_checksum);
+30 -6
View File
@@ -453,8 +453,8 @@ void writeNames(const boost::filesystem::path &path, const NameTableT &table)
serialization::write(writer, "/common/names", table);
}
template <typename NodeWeigtsVectorT>
void readEdgeBasedNodeWeights(const boost::filesystem::path &path, NodeWeigtsVectorT &weights)
template <typename NodeWeightsVectorT>
void readEdgeBasedNodeWeights(const boost::filesystem::path &path, NodeWeightsVectorT &weights)
{
const auto fingerprint = storage::tar::FileReader::VerifyFingerprint;
storage::tar::FileReader reader{path, fingerprint};
@@ -462,9 +462,33 @@ void readEdgeBasedNodeWeights(const boost::filesystem::path &path, NodeWeigtsVec
storage::serialization::read(reader, "/extractor/edge_based_node_weights", weights);
}
template <typename NodeWeigtsVectorT, typename NodeDurationsVectorT>
template <typename NodeDistancesVectorT>
void readEdgeBasedNodeDistances(const boost::filesystem::path &path,
NodeDistancesVectorT &distances)
{
const auto fingerprint = storage::tar::FileReader::VerifyFingerprint;
storage::tar::FileReader reader{path, fingerprint};
storage::serialization::read(reader, "/extractor/edge_based_node_distances", distances);
}
template <typename NodeWeightsVectorT, typename NodeDurationsVectorT, typename NodeDistancesVectorT>
void writeEdgeBasedNodeWeightsDurationsDistances(const boost::filesystem::path &path,
const NodeWeightsVectorT &weights,
const NodeDurationsVectorT &durations,
const NodeDistancesVectorT &distances)
{
const auto fingerprint = storage::tar::FileWriter::GenerateFingerprint;
storage::tar::FileWriter writer{path, fingerprint};
storage::serialization::write(writer, "/extractor/edge_based_node_weights", weights);
storage::serialization::write(writer, "/extractor/edge_based_node_durations", durations);
storage::serialization::write(writer, "/extractor/edge_based_node_distances", distances);
}
template <typename NodeWeightsVectorT, typename NodeDurationsVectorT>
void readEdgeBasedNodeWeightsDurations(const boost::filesystem::path &path,
NodeWeigtsVectorT &weights,
NodeWeightsVectorT &weights,
NodeDurationsVectorT &durations)
{
const auto fingerprint = storage::tar::FileReader::VerifyFingerprint;
@@ -474,9 +498,9 @@ void readEdgeBasedNodeWeightsDurations(const boost::filesystem::path &path,
storage::serialization::read(reader, "/extractor/edge_based_node_durations", durations);
}
template <typename NodeWeigtsVectorT, typename NodeDurationsVectorT>
template <typename NodeWeightsVectorT, typename NodeDurationsVectorT>
void writeEdgeBasedNodeWeightsDurations(const boost::filesystem::path &path,
const NodeWeigtsVectorT &weights,
const NodeWeightsVectorT &weights,
const NodeDurationsVectorT &durations)
{
const auto fingerprint = storage::tar::FileWriter::GenerateFingerprint;
@@ -63,7 +63,7 @@ struct InternalExtractorEdge
WeightData weight_data,
DurationData duration_data,
util::Coordinate source_coordinate)
: result(source, target, 0, 0, {}, -1, {}), weight_data(std::move(weight_data)),
: result(source, target, 0, 0, 0, {}, -1, {}), weight_data(std::move(weight_data)),
duration_data(std::move(duration_data)), source_coordinate(std::move(source_coordinate))
{
}
+18 -6
View File
@@ -97,6 +97,7 @@ struct NodeBasedEdge
NodeID target,
EdgeWeight weight,
EdgeDuration duration,
EdgeDistance distance,
GeometryID geometry_id,
AnnotationID annotation_data,
NodeBasedEdgeClassification flags);
@@ -107,6 +108,7 @@ struct NodeBasedEdge
NodeID target; // 32 4
EdgeWeight weight; // 32 4
EdgeDuration duration; // 32 4
EdgeDistance distance; // 32 4
GeometryID geometry_id; // 32 4
AnnotationID annotation_data; // 32 4
NodeBasedEdgeClassification flags; // 32 4
@@ -120,6 +122,7 @@ struct NodeBasedEdgeWithOSM : NodeBasedEdge
OSMNodeID target,
EdgeWeight weight,
EdgeDuration duration,
EdgeDistance distance,
GeometryID geometry_id,
AnnotationID annotation_data,
NodeBasedEdgeClassification flags);
@@ -137,7 +140,8 @@ inline NodeBasedEdgeClassification::NodeBasedEdgeClassification()
}
inline NodeBasedEdge::NodeBasedEdge()
: source(SPECIAL_NODEID), target(SPECIAL_NODEID), weight(0), duration(0), annotation_data(-1)
: source(SPECIAL_NODEID), target(SPECIAL_NODEID), weight(0), duration(0), distance(0),
annotation_data(-1)
{
}
@@ -145,11 +149,12 @@ inline NodeBasedEdge::NodeBasedEdge(NodeID source,
NodeID target,
EdgeWeight weight,
EdgeDuration duration,
EdgeDistance distance,
GeometryID geometry_id,
AnnotationID annotation_data,
NodeBasedEdgeClassification flags)
: source(source), target(target), weight(weight), duration(duration), geometry_id(geometry_id),
annotation_data(annotation_data), flags(flags)
: source(source), target(target), weight(weight), duration(duration), distance(distance),
geometry_id(geometry_id), annotation_data(annotation_data), flags(flags)
{
}
@@ -175,11 +180,18 @@ inline NodeBasedEdgeWithOSM::NodeBasedEdgeWithOSM(OSMNodeID source,
OSMNodeID target,
EdgeWeight weight,
EdgeDuration duration,
EdgeDistance distance,
GeometryID geometry_id,
AnnotationID annotation_data,
NodeBasedEdgeClassification flags)
: NodeBasedEdge(
SPECIAL_NODEID, SPECIAL_NODEID, weight, duration, geometry_id, annotation_data, flags),
: NodeBasedEdge(SPECIAL_NODEID,
SPECIAL_NODEID,
weight,
duration,
distance,
geometry_id,
annotation_data,
flags),
osm_source_id(std::move(source)), osm_target_id(std::move(target))
{
}
@@ -189,7 +201,7 @@ inline NodeBasedEdgeWithOSM::NodeBasedEdgeWithOSM()
{
}
static_assert(sizeof(extractor::NodeBasedEdge) == 28,
static_assert(sizeof(extractor::NodeBasedEdge) == 32,
"Size of extractor::NodeBasedEdge type is "
"bigger than expected. This will influence "
"memory consumption.");
+130 -5
View File
@@ -2,6 +2,7 @@
#define OSRM_BINDINGS_NODE_SUPPORT_HPP
#include "nodejs/json_v8_renderer.hpp"
#include "util/json_renderer.hpp"
#include "osrm/approach.hpp"
#include "osrm/bearing.hpp"
@@ -24,6 +25,7 @@
#include <algorithm>
#include <iostream>
#include <iterator>
#include <sstream>
#include <string>
#include <vector>
@@ -42,6 +44,13 @@ using match_parameters_ptr = std::unique_ptr<osrm::MatchParameters>;
using nearest_parameters_ptr = std::unique_ptr<osrm::NearestParameters>;
using table_parameters_ptr = std::unique_ptr<osrm::TableParameters>;
struct PluginParameters
{
bool renderJSONToBuffer = false;
};
using ObjectOrString = typename mapbox::util::variant<osrm::json::Object, std::string>;
template <typename ResultT> inline v8::Local<v8::Value> render(const ResultT &result);
template <> v8::Local<v8::Value> inline render(const std::string &result)
@@ -49,11 +58,21 @@ template <> v8::Local<v8::Value> inline render(const std::string &result)
return Nan::CopyBuffer(result.data(), result.size()).ToLocalChecked();
}
template <> v8::Local<v8::Value> inline render(const osrm::json::Object &result)
template <> v8::Local<v8::Value> inline render(const ObjectOrString &result)
{
v8::Local<v8::Value> value;
renderToV8(value, result);
return value;
if (result.is<osrm::json::Object>())
{
// Convert osrm::json object tree into matching v8 object tree
v8::Local<v8::Value> value;
renderToV8(value, result.get<osrm::json::Object>());
return value;
}
else
{
// Return the string object as a node Buffer
return Nan::CopyBuffer(result.get<std::string>().data(), result.get<std::string>().size())
.ToLocalChecked();
}
}
inline void ParseResult(const osrm::Status &result_status, osrm::json::Object &result)
@@ -123,6 +142,10 @@ inline engine_config_ptr argumentsToEngineConfig(const Nan::FunctionCallbackInfo
if (shared_memory.IsEmpty())
return engine_config_ptr();
auto mmap_memory = params->Get(Nan::New("mmap_memory").ToLocalChecked());
if (mmap_memory.IsEmpty())
return engine_config_ptr();
if (!memory_file->IsUndefined())
{
if (path->IsUndefined())
@@ -171,6 +194,18 @@ inline engine_config_ptr argumentsToEngineConfig(const Nan::FunctionCallbackInfo
return engine_config_ptr();
}
}
if (!mmap_memory->IsUndefined())
{
if (mmap_memory->IsBoolean())
{
engine_config->use_mmap = Nan::To<bool>(mmap_memory).FromJust();
}
else
{
Nan::ThrowError("mmap_memory option must be a boolean");
return engine_config_ptr();
}
}
if (path->IsUndefined() && !engine_config->use_shared_memory)
{
@@ -814,6 +849,50 @@ inline bool parseCommonParameters(const v8::Local<v8::Object> &obj, ParamType &p
return true;
}
inline PluginParameters
argumentsToPluginParameters(const Nan::FunctionCallbackInfo<v8::Value> &args)
{
if (args.Length() < 3 || !args[1]->IsObject())
{
return {};
}
v8::Local<v8::Object> obj = Nan::To<v8::Object>(args[1]).ToLocalChecked();
if (obj->Has(Nan::New("format").ToLocalChecked()))
{
v8::Local<v8::Value> format = obj->Get(Nan::New("format").ToLocalChecked());
if (format.IsEmpty())
{
return {};
}
if (!format->IsString())
{
Nan::ThrowError("format must be a string: \"object\" or \"json_buffer\"");
return {};
}
const Nan::Utf8String format_utf8str(format);
std::string format_str{*format_utf8str, *format_utf8str + format_utf8str.length()};
if (format_str == "object")
{
return {false};
}
else if (format_str == "json_buffer")
{
return {true};
}
else
{
Nan::ThrowError("format must be a string: \"object\" or \"json_buffer\"");
return {};
}
}
return {};
}
inline route_parameters_ptr
argumentsToRouteParameter(const Nan::FunctionCallbackInfo<v8::Value> &args,
bool requires_multiple_coordinates)
@@ -1104,6 +1183,52 @@ argumentsToTableParameter(const Nan::FunctionCallbackInfo<v8::Value> &args,
}
}
if (obj->Has(Nan::New("fallback_speed").ToLocalChecked()))
{
auto fallback_speed = obj->Get(Nan::New("fallback_speed").ToLocalChecked());
if (!fallback_speed->IsNumber())
{
Nan::ThrowError("fallback_speed must be a number");
return table_parameters_ptr();
}
else if (fallback_speed->NumberValue() < 0)
{
Nan::ThrowError("fallback_speed must be > 0");
return table_parameters_ptr();
}
params->fallback_speed = static_cast<double>(fallback_speed->NumberValue());
}
if (obj->Has(Nan::New("fallback_coordinate").ToLocalChecked()))
{
auto fallback_coordinate = obj->Get(Nan::New("fallback_coordinate").ToLocalChecked());
if (!fallback_coordinate->IsString())
{
Nan::ThrowError("fallback_coordinate must be a string: [input, snapped]");
return table_parameters_ptr();
}
std::string fallback_coordinate_str = *v8::String::Utf8Value(fallback_coordinate);
if (fallback_coordinate_str == "snapped")
{
params->fallback_coordinate_type =
osrm::TableParameters::FallbackCoordinateType::Snapped;
}
else if (fallback_coordinate_str == "input")
{
params->fallback_coordinate_type = osrm::TableParameters::FallbackCoordinateType::Input;
}
else
{
Nan::ThrowError("'fallback_coordinate' param must be one of [input, snapped]");
return table_parameters_ptr();
}
}
return params;
}
@@ -1357,6 +1482,6 @@ argumentsToMatchParameter(const Nan::FunctionCallbackInfo<v8::Value> &args,
return params;
}
} // ns node_osrm
} // namespace node_osrm
#endif
+33 -14
View File
@@ -75,28 +75,35 @@ template <storage::Ownership Ownership> class CellStorageImpl
// Implementation of the cell view. We need a template parameter here
// because we need to derive a read-only and read-write view from this.
template <typename WeightValueT, typename DurationValueT> class CellImpl
template <typename WeightValueT, typename DurationValueT, typename DistanceValueT>
class CellImpl
{
private:
using WeightPtrT = WeightValueT *;
using DurationPtrT = DurationValueT *;
using DistancePtrT = DistanceValueT *;
BoundarySize num_source_nodes;
BoundarySize num_destination_nodes;
WeightPtrT const weights;
DurationPtrT const durations;
DistancePtrT const distances;
const NodeID *const source_boundary;
const NodeID *const destination_boundary;
using RowIterator = WeightPtrT;
// Possibly replace with
// http://www.boost.org/doc/libs/1_55_0/libs/range/doc/html/range/reference/adaptors/reference/strided.html
class ColumnIterator : public boost::iterator_facade<ColumnIterator,
WeightValueT,
template <typename ValuePtrT>
class ColumnIterator : public boost::iterator_facade<ColumnIterator<ValuePtrT>,
decltype(*std::declval<ValuePtrT>()),
boost::random_access_traversal_tag>
{
typedef boost::iterator_facade<ColumnIterator,
WeightValueT,
using ValueT = decltype(*std::declval<ValuePtrT>());
typedef boost::iterator_facade<ColumnIterator<ValueT>,
ValueT,
boost::random_access_traversal_tag>
base_t;
@@ -108,7 +115,7 @@ template <storage::Ownership Ownership> class CellStorageImpl
explicit ColumnIterator() : current(nullptr), stride(1) {}
explicit ColumnIterator(WeightPtrT begin, std::size_t row_length)
explicit ColumnIterator(ValuePtrT begin, std::size_t row_length)
: current(begin), stride(row_length)
{
BOOST_ASSERT(begin != nullptr);
@@ -126,7 +133,7 @@ template <storage::Ownership Ownership> class CellStorageImpl
}
friend class ::boost::iterator_core_access;
WeightPtrT current;
ValuePtrT current;
const std::size_t stride;
};
@@ -147,12 +154,13 @@ template <storage::Ownership Ownership> class CellStorageImpl
auto iter =
std::find(destination_boundary, destination_boundary + num_destination_nodes, node);
if (iter == destination_boundary + num_destination_nodes)
return boost::make_iterator_range(ColumnIterator{}, ColumnIterator{});
return boost::make_iterator_range(ColumnIterator<ValuePtr>{},
ColumnIterator<ValuePtr>{});
auto column = std::distance(destination_boundary, iter);
auto begin = ColumnIterator{ptr + column, num_destination_nodes};
auto end = ColumnIterator{ptr + column + num_source_nodes * num_destination_nodes,
num_destination_nodes};
auto begin = ColumnIterator<ValuePtr>{ptr + column, num_destination_nodes};
auto end = ColumnIterator<ValuePtr>{
ptr + column + num_source_nodes * num_destination_nodes, num_destination_nodes};
return boost::make_iterator_range(begin, end);
}
@@ -165,6 +173,10 @@ template <storage::Ownership Ownership> class CellStorageImpl
auto GetInDuration(NodeID node) const { return GetInRange(durations, node); }
auto GetInDistance(NodeID node) const { return GetInRange(distances, node); }
auto GetOutDistance(NodeID node) const { return GetOutRange(distances, node); }
auto GetSourceNodes() const
{
return boost::make_iterator_range(source_boundary, source_boundary + num_source_nodes);
@@ -179,17 +191,20 @@ template <storage::Ownership Ownership> class CellStorageImpl
CellImpl(const CellData &data,
WeightPtrT const all_weights,
DurationPtrT const all_durations,
DistancePtrT const all_distances,
const NodeID *const all_sources,
const NodeID *const all_destinations)
: num_source_nodes{data.num_source_nodes},
num_destination_nodes{data.num_destination_nodes},
weights{all_weights + data.value_offset},
durations{all_durations + data.value_offset},
distances{all_distances + data.value_offset},
source_boundary{all_sources + data.source_boundary_offset},
destination_boundary{all_destinations + data.destination_boundary_offset}
{
BOOST_ASSERT(all_weights != nullptr);
BOOST_ASSERT(all_durations != nullptr);
BOOST_ASSERT(all_distances != nullptr);
BOOST_ASSERT(num_source_nodes == 0 || all_sources != nullptr);
BOOST_ASSERT(num_destination_nodes == 0 || all_destinations != nullptr);
}
@@ -201,7 +216,8 @@ template <storage::Ownership Ownership> class CellStorageImpl
const NodeID *const all_destinations)
: num_source_nodes{data.num_source_nodes},
num_destination_nodes{data.num_destination_nodes}, weights{nullptr},
durations{nullptr}, source_boundary{all_sources + data.source_boundary_offset},
durations{nullptr}, distances{nullptr},
source_boundary{all_sources + data.source_boundary_offset},
destination_boundary{all_destinations + data.destination_boundary_offset}
{
BOOST_ASSERT(num_source_nodes == 0 || all_sources != nullptr);
@@ -212,8 +228,8 @@ template <storage::Ownership Ownership> class CellStorageImpl
std::size_t LevelIDToIndex(LevelID level) const { return level - 1; }
public:
using Cell = CellImpl<EdgeWeight, EdgeDuration>;
using ConstCell = CellImpl<const EdgeWeight, const EdgeDuration>;
using Cell = CellImpl<EdgeWeight, EdgeDuration, EdgeDistance>;
using ConstCell = CellImpl<const EdgeWeight, const EdgeDuration, const EdgeDistance>;
CellStorageImpl() {}
@@ -361,6 +377,7 @@ template <storage::Ownership Ownership> class CellStorageImpl
metric.weights.resize(total_size + 1, INVALID_EDGE_WEIGHT);
metric.durations.resize(total_size + 1, MAXIMAL_EDGE_DURATION);
metric.distances.resize(total_size + 1, INVALID_EDGE_DISTANCE);
return metric;
}
@@ -388,6 +405,7 @@ template <storage::Ownership Ownership> class CellStorageImpl
return ConstCell{cells[cell_index],
metric.weights.data(),
metric.durations.data(),
metric.distances.data(),
source_boundary.empty() ? nullptr : source_boundary.data(),
destination_boundary.empty() ? nullptr : destination_boundary.data()};
}
@@ -415,6 +433,7 @@ template <storage::Ownership Ownership> class CellStorageImpl
return Cell{cells[cell_index],
metric.weights.data(),
metric.durations.data(),
metric.distances.data(),
source_boundary.data(),
destination_boundary.data()};
}
@@ -43,6 +43,7 @@ splitBidirectionalEdges(const std::vector<extractor::EdgeBasedEdge> &edges)
edge.data.turn_id,
std::max(edge.data.weight, 1),
edge.data.duration,
edge.data.distance,
edge.data.forward,
edge.data.backward);
@@ -51,6 +52,7 @@ splitBidirectionalEdges(const std::vector<extractor::EdgeBasedEdge> &edges)
edge.data.turn_id,
std::max(edge.data.weight, 1),
edge.data.duration,
edge.data.distance,
edge.data.backward,
edge.data.forward);
}
@@ -178,6 +178,8 @@ struct BaseParametersGrammar : boost::spirit::qi::grammar<Iterator, Signature>
qi::rule<Iterator, Signature> base_rule;
qi::rule<Iterator, Signature> query_rule;
qi::real_parser<double, json_policy> double_;
private:
qi::rule<Iterator, Signature> bearings_rule;
qi::rule<Iterator, Signature> radiuses_rule;
@@ -195,7 +197,6 @@ struct BaseParametersGrammar : boost::spirit::qi::grammar<Iterator, Signature>
qi::rule<Iterator, unsigned char()> base64_char;
qi::rule<Iterator, std::string()> polyline_chars;
qi::rule<Iterator, double()> unlimited_rule;
qi::real_parser<double, json_policy> double_;
qi::symbols<char, engine::Approach> approach_type;
};
+22 -2
View File
@@ -48,10 +48,24 @@ struct TableParametersGrammar : public BaseParametersGrammar<Iterator, Signature
(qi::lit("all") |
(size_t_ % ';')[ph::bind(&engine::api::TableParameters::sources, qi::_r1) = qi::_1]);
fallback_speed_rule =
qi::lit("fallback_speed=") >
(double_)[ph::bind(&engine::api::TableParameters::fallback_speed, qi::_r1) = qi::_1];
fallback_coordinate_type.add("input",
engine::api::TableParameters::FallbackCoordinateType::Input)(
"snapped", engine::api::TableParameters::FallbackCoordinateType::Snapped);
table_rule = destinations_rule(qi::_r1) | sources_rule(qi::_r1);
root_rule = BaseGrammar::query_rule(qi::_r1) > -qi::lit(".json") >
-('?' > (table_rule(qi::_r1) | base_rule(qi::_r1)) % '&');
root_rule =
BaseGrammar::query_rule(qi::_r1) > -qi::lit(".json") >
-('?' > (table_rule(qi::_r1) | base_rule(qi::_r1) | fallback_speed_rule(qi::_r1) |
(qi::lit("fallback_coordinate=") >
fallback_coordinate_type
[ph::bind(&engine::api::TableParameters::fallback_coordinate_type,
qi::_r1) = qi::_1])) %
'&');
}
TableParametersGrammar(qi::rule<Iterator, Signature> &root_rule_) : BaseGrammar(root_rule_)
@@ -73,13 +87,19 @@ struct TableParametersGrammar : public BaseParametersGrammar<Iterator, Signature
qi::rule<Iterator, Signature> base_rule;
private:
using json_policy = no_trailing_dot_policy<double, 'j', 's', 'o', 'n'>;
qi::rule<Iterator, Signature> root_rule;
qi::rule<Iterator, Signature> table_rule;
qi::rule<Iterator, Signature> sources_rule;
qi::rule<Iterator, Signature> destinations_rule;
qi::rule<Iterator, Signature> fallback_speed_rule;
qi::rule<Iterator, std::size_t()> size_t_;
qi::symbols<char, engine::api::TableParameters::AnnotationsType> annotations;
qi::rule<Iterator, engine::api::TableParameters::AnnotationsType()> annotations_list;
qi::symbols<char, engine::api::TableParameters::FallbackCoordinateType>
fallback_coordinate_type;
qi::real_parser<double, json_policy> double_;
};
}
}
+8 -3
View File
@@ -16,10 +16,15 @@ struct Block
{
std::uint64_t num_entries;
std::uint64_t byte_size;
std::uint64_t offset;
Block() : num_entries(0), byte_size(0) {}
Block() : num_entries(0), byte_size(0), offset(0) {}
Block(std::uint64_t num_entries, std::uint64_t byte_size, std::uint64_t offset)
: num_entries(num_entries), byte_size(byte_size), offset(offset)
{
}
Block(std::uint64_t num_entries, std::uint64_t byte_size)
: num_entries(num_entries), byte_size(byte_size)
: num_entries(num_entries), byte_size(byte_size), offset(0)
{
}
};
@@ -29,7 +34,7 @@ using NamedBlock = std::tuple<std::string, Block>;
template <typename T> Block make_block(uint64_t num_entries)
{
static_assert(sizeof(T) % alignof(T) == 0, "aligned T* can't be used as an array pointer");
return Block{num_entries, sizeof(T) * num_entries};
return Block{num_entries, sizeof(T) * num_entries, 0};
}
}
}
+40 -22
View File
@@ -9,6 +9,7 @@
#include "storage/shared_datatype.hpp"
#include "storage/tar.hpp"
#include <boost/assert.hpp>
#include <boost/function_output_iterator.hpp>
#include <boost/iterator/function_input_iterator.hpp>
@@ -30,22 +31,37 @@ namespace serialization
namespace detail
{
template <typename T, typename BlockT = unsigned char>
inline BlockT packBits(const T &data, std::size_t index, std::size_t count)
inline BlockT packBits(const T &data, std::size_t base_index, const std::size_t count)
{
static_assert(std::is_same<typename T::value_type, bool>::value, "value_type is not bool");
static_assert(std::is_unsigned<BlockT>::value, "BlockT must be unsigned type");
static_assert(std::is_integral<BlockT>::value, "BlockT must be an integral type");
static_assert(CHAR_BIT == 8, "Non-8-bit bytes not supported, sorry!");
BOOST_ASSERT(sizeof(BlockT) * CHAR_BIT >= count);
// Note: if this packing is changed, be sure to update vector_view<bool>
// as well, so that on-disk and in-memory layouts match.
BlockT value = 0;
for (std::size_t bit = 0; bit < count; ++bit, ++index)
value = (value << 1) | data[index];
for (std::size_t bit = 0; bit < count; ++bit)
{
value |= (data[base_index + bit] ? BlockT{1} : BlockT{0}) << bit;
}
return value;
}
template <typename T, typename BlockT = unsigned char>
inline void unpackBits(T &data, std::size_t index, std::size_t count, BlockT value)
inline void
unpackBits(T &data, const std::size_t base_index, const std::size_t count, const BlockT value)
{
static_assert(std::is_same<typename T::value_type, bool>::value, "value_type is not bool");
const BlockT mask = BlockT{1} << (count - 1);
for (std::size_t bit = 0; bit < count; value <<= 1, ++bit, ++index)
data[index] = value & mask;
static_assert(std::is_unsigned<BlockT>::value, "BlockT must be unsigned type");
static_assert(std::is_integral<BlockT>::value, "BlockT must be an integral type");
static_assert(CHAR_BIT == 8, "Non-8-bit bytes not supported, sorry!");
BOOST_ASSERT(sizeof(BlockT) * CHAR_BIT >= count);
for (std::size_t bit = 0; bit < count; ++bit)
{
data[base_index + bit] = value & (BlockT{1} << bit);
}
}
template <typename VectorT>
@@ -55,15 +71,16 @@ void readBoolVector(tar::FileReader &reader, const std::string &name, VectorT &d
data.resize(count);
std::uint64_t index = 0;
constexpr std::uint64_t WORD_BITS = CHAR_BIT * sizeof(std::uint64_t);
using BlockType = std::uint64_t;
constexpr std::uint64_t BLOCK_BITS = CHAR_BIT * sizeof(BlockType);
const auto decode = [&](const std::uint64_t block) {
auto read_size = std::min<std::size_t>(count - index, WORD_BITS);
unpackBits<VectorT, std::uint64_t>(data, index, read_size, block);
index += WORD_BITS;
const auto decode = [&](const BlockType block) {
auto read_size = std::min<std::size_t>(count - index, BLOCK_BITS);
unpackBits<VectorT, BlockType>(data, index, read_size, block);
index += BLOCK_BITS;
};
reader.ReadStreaming<std::uint64_t>(name, boost::make_function_output_iterator(decode));
reader.ReadStreaming<BlockType>(name, boost::make_function_output_iterator(decode));
}
template <typename VectorT>
@@ -73,19 +90,20 @@ void writeBoolVector(tar::FileWriter &writer, const std::string &name, const Vec
writer.WriteElementCount64(name, count);
std::uint64_t index = 0;
constexpr std::uint64_t WORD_BITS = CHAR_BIT * sizeof(std::uint64_t);
using BlockType = std::uint64_t;
constexpr std::uint64_t BLOCK_BITS = CHAR_BIT * sizeof(BlockType);
// FIXME on old boost version the function_input_iterator does not work with lambdas
// so we need to wrap it in a function here.
const std::function<std::uint64_t()> encode_function = [&]() -> std::uint64_t {
auto write_size = std::min<std::size_t>(count - index, WORD_BITS);
auto packed = packBits<VectorT, std::uint64_t>(data, index, write_size);
index += WORD_BITS;
const std::function<BlockType()> encode_function = [&]() -> BlockType {
auto write_size = std::min<std::size_t>(count - index, BLOCK_BITS);
auto packed = packBits<VectorT, BlockType>(data, index, write_size);
index += BLOCK_BITS;
return packed;
};
std::uint64_t number_of_blocks = (count + WORD_BITS - 1) / WORD_BITS;
writer.WriteStreaming<std::uint64_t>(
std::uint64_t number_of_blocks = (count + BLOCK_BITS - 1) / BLOCK_BITS;
writer.WriteStreaming<BlockType>(
name,
boost::make_function_input_iterator(encode_function, boost::infinite()),
number_of_blocks);
@@ -266,9 +284,9 @@ template <typename K, typename V> void write(io::BufferWriter &writer, const std
}
}
inline void read(io::BufferReader &reader, DataLayout &layout) { read(reader, layout.blocks); }
inline void read(io::BufferReader &reader, BaseDataLayout &layout) { read(reader, layout.blocks); }
inline void write(io::BufferWriter &writer, const DataLayout &layout)
inline void write(io::BufferWriter &writer, const BaseDataLayout &layout)
{
write(writer, layout.blocks);
}
+24 -11
View File
@@ -5,6 +5,7 @@
#include <boost/function_output_iterator.hpp>
#include <type_traits>
#include <unordered_map>
namespace osrm
@@ -19,8 +20,8 @@ class SharedDataIndex
public:
struct AllocatedRegion
{
char *memory_ptr;
DataLayout layout;
void *memory_ptr;
std::unique_ptr<BaseDataLayout> layout;
};
SharedDataIndex() = default;
@@ -29,10 +30,10 @@ class SharedDataIndex
// Build mapping from block name to region
for (auto index : util::irange<std::uint32_t>(0, regions.size()))
{
regions[index].layout.List("",
boost::make_function_output_iterator([&](const auto &name) {
block_to_region[name] = index;
}));
regions[index].layout->List("",
boost::make_function_output_iterator([&](const auto &name) {
block_to_region[name] = index;
}));
}
}
@@ -40,32 +41,44 @@ class SharedDataIndex
{
for (const auto &region : regions)
{
region.layout.List(name_prefix, out);
region.layout->List(name_prefix, out);
}
}
template <typename T> auto GetBlockPtr(const std::string &name) const
{
#if !defined(__GNUC__) || (__GNUC__ > 4)
// is_tivially_copyable only exists in GCC >=5
static_assert(std::is_trivially_copyable<T>::value,
"Block-based data must be a trivially copyable type");
static_assert(sizeof(T) % alignof(T) == 0, "aligned T* can't be used as an array pointer");
#endif
const auto &region = GetBlockRegion(name);
return region.layout.GetBlockPtr<T>(region.memory_ptr, name);
return reinterpret_cast<T *>(region.layout->GetBlockPtr(region.memory_ptr, name));
}
template <typename T> auto GetBlockPtr(const std::string &name)
{
#if !defined(__GNUC__) || (__GNUC__ > 4)
// is_tivially_copyable only exists in GCC >=5
static_assert(std::is_trivially_copyable<T>::value,
"Block-based data must be a trivially copyable type");
static_assert(sizeof(T) % alignof(T) == 0, "aligned T* can't be used as an array pointer");
#endif
const auto &region = GetBlockRegion(name);
return region.layout.GetBlockPtr<T>(region.memory_ptr, name);
return reinterpret_cast<T *>(region.layout->GetBlockPtr(region.memory_ptr, name));
}
std::size_t GetBlockEntries(const std::string &name) const
{
const auto &region = GetBlockRegion(name);
return region.layout.GetBlockEntries(name);
return region.layout->GetBlockEntries(name);
}
std::size_t GetBlockSize(const std::string &name) const
{
const auto &region = GetBlockRegion(name);
return region.layout.GetBlockSize(name);
return region.layout->GetBlockSize(name);
}
private:
+76 -41
View File
@@ -20,13 +20,13 @@ namespace osrm
namespace storage
{
class DataLayout;
class BaseDataLayout;
namespace serialization
{
inline void read(io::BufferReader &reader, DataLayout &layout);
inline void read(io::BufferReader &reader, BaseDataLayout &layout);
inline void write(io::BufferWriter &writer, const DataLayout &layout);
}
inline void write(io::BufferWriter &writer, const BaseDataLayout &layout);
} // namespace serialization
namespace detail
{
@@ -52,46 +52,30 @@ inline std::string trimName(const std::string &name_prefix, const std::string &n
return name;
}
}
}
} // namespace detail
class DataLayout
class BaseDataLayout
{
public:
DataLayout() : blocks{} {}
virtual ~BaseDataLayout() = default;
inline void SetBlock(const std::string &name, Block block) { blocks[name] = std::move(block); }
inline uint64_t GetBlockEntries(const std::string &name) const
inline std::uint64_t GetBlockEntries(const std::string &name) const
{
return GetBlock(name).num_entries;
}
inline uint64_t GetBlockSize(const std::string &name) const { return GetBlock(name).byte_size; }
inline std::uint64_t GetBlockSize(const std::string &name) const
{
return GetBlock(name).byte_size;
}
inline bool HasBlock(const std::string &name) const
{
return blocks.find(name) != blocks.end();
}
inline uint64_t GetSizeOfLayout() const
{
uint64_t result = 0;
for (const auto &name_and_block : blocks)
{
result += GetBlockSize(name_and_block.first) + BLOCK_ALIGNMENT;
}
return result;
}
template <typename T> inline T *GetBlockPtr(char *shared_memory, const std::string &name) const
{
static_assert(BLOCK_ALIGNMENT % std::alignment_of<T>::value == 0,
"Datatype does not fit alignment constraints.");
char *ptr = (char *)GetAlignedBlockPtr(shared_memory, name);
return (T *)ptr;
}
// Depending on the name prefix this function either lists all blocks with the same prefix
// or all entries in the sub-directory.
// '/ch/edge' -> '/ch/edge_filter/0/blocks', '/ch/edge_filter/1/blocks'
@@ -115,10 +99,10 @@ class DataLayout
}
}
private:
friend void serialization::read(io::BufferReader &reader, DataLayout &layout);
friend void serialization::write(io::BufferWriter &writer, const DataLayout &layout);
virtual inline void *GetBlockPtr(void *base_ptr, const std::string &name) const = 0;
virtual inline std::uint64_t GetSizeOfLayout() const = 0;
protected:
const Block &GetBlock(const std::string &name) const
{
auto iter = blocks.find(name);
@@ -130,10 +114,42 @@ class DataLayout
return iter->second;
}
friend void serialization::read(io::BufferReader &reader, BaseDataLayout &layout);
friend void serialization::write(io::BufferWriter &writer, const BaseDataLayout &layout);
std::map<std::string, Block> blocks;
};
class ContiguousDataLayout final : public BaseDataLayout
{
public:
inline std::uint64_t GetSizeOfLayout() const override final
{
std::uint64_t result = 0;
for (const auto &name_and_block : blocks)
{
result += GetBlockSize(name_and_block.first) + BLOCK_ALIGNMENT;
}
return result;
}
inline void *GetBlockPtr(void *base_ptr, const std::string &name) const override final
{
// TODO: re-enable this alignment checking somehow
// static_assert(BLOCK_ALIGNMENT % std::alignment_of<T>::value == 0,
// "Datatype does not fit alignment constraints.");
return GetAlignedBlockPtr(base_ptr, name);
}
private:
friend void serialization::read(io::BufferReader &reader, BaseDataLayout &layout);
friend void serialization::write(io::BufferWriter &writer, const BaseDataLayout &layout);
// Fit aligned storage in buffer to 64 bytes to conform with AVX 512 types
inline void *align(void *&ptr) const noexcept
{
const auto intptr = reinterpret_cast<uintptr_t>(ptr);
const auto intptr = reinterpret_cast<std::uintptr_t>(ptr);
const auto aligned = (intptr - 1u + BLOCK_ALIGNMENT) & -BLOCK_ALIGNMENT;
return ptr = reinterpret_cast<void *>(aligned);
}
@@ -157,7 +173,27 @@ class DataLayout
}
static constexpr std::size_t BLOCK_ALIGNMENT = 64;
std::map<std::string, Block> blocks;
};
class TarDataLayout final : public BaseDataLayout
{
public:
inline std::uint64_t GetSizeOfLayout() const override final
{
std::uint64_t result = 0;
for (const auto &name_and_block : blocks)
{
result += GetBlockSize(name_and_block.first);
}
return result;
}
inline void *GetBlockPtr(void *base_ptr, const std::string &name) const override final
{
auto offset = GetBlock(name).offset;
const auto offset_address = reinterpret_cast<std::uintptr_t>(base_ptr) + offset;
return reinterpret_cast<void *>(offset_address);
}
};
struct SharedRegion
@@ -165,7 +201,7 @@ struct SharedRegion
static constexpr const int MAX_NAME_LENGTH = 254;
SharedRegion() : name{0}, timestamp{0} {}
SharedRegion(const std::string &name_, std::uint64_t timestamp, std::uint8_t shm_key)
SharedRegion(const std::string &name_, std::uint64_t timestamp, std::uint16_t shm_key)
: name{0}, timestamp{timestamp}, shm_key{shm_key}
{
std::copy_n(name_.begin(), std::min<std::size_t>(MAX_NAME_LENGTH, name_.size()), name);
@@ -175,14 +211,14 @@ struct SharedRegion
char name[MAX_NAME_LENGTH + 1];
std::uint64_t timestamp;
std::uint8_t shm_key;
std::uint16_t shm_key;
};
// Keeps a list of all shared regions in a fixed-sized struct
// for fast access and deserialization.
struct SharedRegionRegister
{
using RegionID = std::uint8_t;
using RegionID = std::uint16_t;
static constexpr const RegionID INVALID_REGION_ID = std::numeric_limits<RegionID>::max();
using ShmKey = decltype(SharedRegion::shm_key);
@@ -250,12 +286,11 @@ struct SharedRegionRegister
void ReleaseKey(ShmKey key) { shm_key_in_use[key] = false; }
static constexpr const std::uint8_t MAX_SHARED_REGIONS =
std::numeric_limits<RegionID>::max() - 1;
static constexpr const std::size_t MAX_SHARED_REGIONS = 512;
static_assert(MAX_SHARED_REGIONS < std::numeric_limits<RegionID>::max(),
"Number of shared memory regions needs to be less than the region id size.");
static constexpr const std::uint8_t MAX_SHM_KEYS = std::numeric_limits<std::uint8_t>::max() - 1;
static constexpr const std::size_t MAX_SHM_KEYS = MAX_SHARED_REGIONS * 2;
static constexpr const char *name = "osrm-region";
@@ -263,7 +298,7 @@ struct SharedRegionRegister
std::array<SharedRegion, MAX_SHARED_REGIONS> regions;
std::array<bool, MAX_SHM_KEYS> shm_key_in_use;
};
}
}
} // namespace storage
} // namespace osrm
#endif /* SHARED_DATA_TYPE_HPP */
+10 -9
View File
@@ -34,10 +34,10 @@ namespace storage
struct OSRMLockFile
{
boost::filesystem::path operator()()
template <typename IdentifierT> boost::filesystem::path operator()(const IdentifierT &id)
{
boost::filesystem::path temp_dir = boost::filesystem::temp_directory_path();
boost::filesystem::path lock_file = temp_dir / "osrm.lock";
boost::filesystem::path lock_file = temp_dir / ("osrm-" + std::to_string(id) + ".lock");
return lock_file;
}
};
@@ -93,7 +93,7 @@ class SharedMemory
try
{
OSRMLockFile lock_file;
boost::interprocess::xsi_key key(lock_file().string().c_str(), id);
boost::interprocess::xsi_key key(lock_file(id).string().c_str(), id);
result = RegionExists(key);
}
catch (...)
@@ -106,7 +106,7 @@ class SharedMemory
template <typename IdentifierT> static bool Remove(const IdentifierT id)
{
OSRMLockFile lock_file;
boost::interprocess::xsi_key key(lock_file().string().c_str(), id);
boost::interprocess::xsi_key key(lock_file(id).string().c_str(), id);
return Remove(key);
}
@@ -287,10 +287,11 @@ class SharedMemory
template <typename IdentifierT, typename LockFileT = OSRMLockFile>
std::unique_ptr<SharedMemory> makeSharedMemory(const IdentifierT &id, const uint64_t size = 0)
{
static_assert(sizeof(id) == sizeof(std::uint16_t), "Key type is not 16 bits");
try
{
LockFileT lock_file;
if (!boost::filesystem::exists(lock_file()))
if (!boost::filesystem::exists(lock_file(id)))
{
if (0 == size)
{
@@ -298,10 +299,10 @@ std::unique_ptr<SharedMemory> makeSharedMemory(const IdentifierT &id, const uint
}
else
{
boost::filesystem::ofstream ofs(lock_file());
boost::filesystem::ofstream ofs(lock_file(id));
}
}
return std::make_unique<SharedMemory>(lock_file(), id, size);
return std::make_unique<SharedMemory>(lock_file(id), id, size);
}
catch (const boost::interprocess::interprocess_exception &e)
{
@@ -310,7 +311,7 @@ std::unique_ptr<SharedMemory> makeSharedMemory(const IdentifierT &id, const uint
throw util::exception(e.what() + SOURCE_REF);
}
}
}
}
} // namespace storage
} // namespace osrm
#endif // SHARED_MEMORY_HPP
+6 -4
View File
@@ -33,7 +33,7 @@ template <class Lock> class InvertedLock
InvertedLock(Lock &lock) : lock(lock) { lock.unlock(); }
~InvertedLock() { lock.lock(); }
};
}
} // namespace
// The shared monitor implementation based on a semaphore and mutex
template <typename Data> struct SharedMonitor
@@ -146,7 +146,9 @@ template <typename Data> struct SharedMonitor
// like two-turnstile reusable barrier or boost/interprocess/sync/spin/condition.hpp
// fail if a waiter is killed.
static constexpr int buffer_size = 256;
// Buffer size needs to be large enough to hold all the semaphores for every
// listener you want to support.
static constexpr int buffer_size = 4096 * 4;
struct InternalData
{
@@ -232,8 +234,8 @@ template <typename Data> struct SharedMonitor
bi::shared_memory_object shmem;
bi::mapped_region region;
};
}
}
} // namespace storage
} // namespace osrm
#undef USE_BOOST_INTERPROCESS_CONDITION
+9 -3
View File
@@ -35,22 +35,28 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <boost/filesystem/path.hpp>
#include <string>
#include <vector>
namespace osrm
{
namespace storage
{
void populateLayoutFromFile(const boost::filesystem::path &path, storage::BaseDataLayout &layout);
class Storage
{
public:
Storage(StorageConfig config);
int Run(int max_wait, const std::string &name, bool only_metric);
void PopulateStaticLayout(DataLayout &layout);
void PopulateUpdatableLayout(DataLayout &layout);
void PopulateStaticData(const SharedDataIndex &index);
void PopulateUpdatableData(const SharedDataIndex &index);
void PopulateLayout(storage::BaseDataLayout &layout,
const std::vector<std::pair<bool, boost::filesystem::path>> &files);
std::string PopulateLayoutWithRTree(storage::BaseDataLayout &layout);
std::vector<std::pair<bool, boost::filesystem::path>> GetUpdatableFiles();
std::vector<std::pair<bool, boost::filesystem::path>> GetStaticFiles();
private:
StorageConfig config;
+10 -3
View File
@@ -294,11 +294,14 @@ inline auto make_filtered_cell_metric_view(const SharedDataIndex &index,
auto prefix = name + "/exclude/" + std::to_string(exclude_index);
auto weights_block_id = prefix + "/weights";
auto durations_block_id = prefix + "/durations";
auto distances_block_id = prefix + "/distances";
auto weights = make_vector_view<EdgeWeight>(index, weights_block_id);
auto durations = make_vector_view<EdgeDuration>(index, durations_block_id);
auto distances = make_vector_view<EdgeDistance>(index, distances_block_id);
return customizer::CellMetricView{std::move(weights), std::move(durations)};
return customizer::CellMetricView{
std::move(weights), std::move(durations), std::move(distances)};
}
inline auto make_cell_metric_view(const SharedDataIndex &index, const std::string &name)
@@ -311,12 +314,14 @@ inline auto make_cell_metric_view(const SharedDataIndex &index, const std::strin
{
auto weights_block_id = prefix + "/weights";
auto durations_block_id = prefix + "/durations";
auto distances_block_id = prefix + "/distances";
auto weights = make_vector_view<EdgeWeight>(index, weights_block_id);
auto durations = make_vector_view<EdgeDuration>(index, durations_block_id);
auto distances = make_vector_view<EdgeDistance>(index, distances_block_id);
cell_metric_excludes.push_back(
customizer::CellMetricView{std::move(weights), std::move(durations)});
cell_metric_excludes.push_back(customizer::CellMetricView{
std::move(weights), std::move(durations), std::move(distances)});
}
return cell_metric_excludes;
@@ -332,6 +337,7 @@ inline auto make_multi_level_graph_view(const SharedDataIndex &index, const std:
index, name + "/node_to_edge_offset");
auto node_weights = make_vector_view<EdgeWeight>(index, name + "/node_weights");
auto node_durations = make_vector_view<EdgeDuration>(index, name + "/node_durations");
auto node_distances = make_vector_view<EdgeDistance>(index, name + "/node_distances");
auto is_forward_edge = make_vector_view<bool>(index, name + "/is_forward_edge");
auto is_backward_edge = make_vector_view<bool>(index, name + "/is_backward_edge");
@@ -340,6 +346,7 @@ inline auto make_multi_level_graph_view(const SharedDataIndex &index, const std:
std::move(node_to_offset),
std::move(node_weights),
std::move(node_durations),
std::move(node_distances),
std::move(is_forward_edge),
std::move(is_backward_edge));
}
+11 -5
View File
@@ -22,11 +22,17 @@ class Updater
std::vector<EdgeWeight> &node_weights,
std::uint32_t &connectivity_checksum) const;
EdgeID
LoadAndUpdateEdgeExpandedGraph(std::vector<extractor::EdgeBasedEdge> &edge_based_edge_list,
std::vector<EdgeWeight> &node_weights,
std::vector<EdgeDuration> &node_durations, // TODO: to be deleted
std::uint32_t &connectivity_checksum) const;
EdgeID LoadAndUpdateEdgeExpandedGraph(
std::vector<extractor::EdgeBasedEdge> &edge_based_edge_list,
std::vector<EdgeWeight> &node_weights,
std::vector<EdgeDuration> &node_durations, // TODO: remove when optional
std::uint32_t &connectivity_checksum) const;
EdgeID LoadAndUpdateEdgeExpandedGraph(
std::vector<extractor::EdgeBasedEdge> &edge_based_edge_list,
std::vector<EdgeWeight> &node_weights,
std::vector<EdgeDuration> &node_durations, // TODO: remove when optional
std::vector<EdgeDistance> &node_distances, // TODO: remove when optional
std::uint32_t &connectivity_checksum) const;
private:
UpdaterConfig config;
+3
View File
@@ -23,6 +23,9 @@ namespace detail
{
const constexpr double DEGREE_TO_RAD = 0.017453292519943295769236907684886;
const constexpr double RAD_TO_DEGREE = 1. / DEGREE_TO_RAD;
// earth radius varies between 6,356.750-6,378.135 km (3,949.901-3,963.189mi)
// The IUGG value for the equatorial radius is 6378.137 km (3963.19 miles)
const constexpr long double EARTH_RADIUS = 6372797.560856;
inline double degToRad(const double degree)
{
+19
View File
@@ -1,9 +1,11 @@
#ifndef OSRM_UTIL_DEBUG_HPP_
#define OSRM_UTIL_DEBUG_HPP_
#include "extractor/edge_based_edge.hpp"
#include "extractor/node_data_container.hpp"
#include "extractor/query_node.hpp"
#include "guidance/intersection.hpp"
#include "guidance/turn_instruction.hpp"
#include "guidance/turn_lane_data.hpp"
#include "engine/guidance/route_step.hpp"
#include "util/node_based_graph.hpp"
@@ -186,6 +188,23 @@ inline std::ostream &operator<<(std::ostream &out, const LaneDataVector &turn_la
}
}
}
namespace extractor
{
inline std::ostream &operator<<(std::ostream &out, const EdgeBasedEdge &edge)
{
out << " EdgeBasedEdge {";
out << " source " << edge.source << ", target: " << edge.target;
out << " EdgeBasedEdgeData data {";
out << " turn_id: " << edge.data.turn_id << ", weight: " << edge.data.weight;
out << " distance: " << edge.data.distance << ", duration: " << edge.data.duration;
out << " forward: " << (edge.data.forward == 0 ? "false" : "true")
<< ", backward: " << (edge.data.backward == 0 ? "false" : "true");
out << " }";
out << "}";
return out;
}
}
}
#endif /*OSRM_ENGINE_GUIDANCE_DEBUG_HPP_*/
+517
View File
@@ -0,0 +1,517 @@
#ifndef IEEE754_HPP
#define IEEE754_HPP
/**
Copyright (C) 2014 Milo Yip
Imported from:
https://github.com/miloyip/dtoa-benchmark/blob/c4020c62754950d38a1aaaed2975b05b441d1e7d/src/milo/dtoa_milo.h
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
**/
#include <assert.h>
#include <math.h>
#if defined(_MSC_VER)
#include "rapidjson/msinttypes/stdint.h"
#include <intrin.h>
#else
#include <stdint.h>
#endif
#define UINT64_C2(h, l) ((static_cast<uint64_t>(h) << 32) | static_cast<uint64_t>(l))
namespace osrm
{
namespace util
{
namespace ieee754
{
struct DiyFp
{
DiyFp() {}
DiyFp(uint64_t f, int e) : f(f), e(e) {}
DiyFp(double d)
{
union {
double d;
uint64_t u64;
} u = {d};
int biased_e = (u.u64 & kDpExponentMask) >> kDpSignificandSize;
uint64_t significand = (u.u64 & kDpSignificandMask);
if (biased_e != 0)
{
f = significand + kDpHiddenBit;
e = biased_e - kDpExponentBias;
}
else
{
f = significand;
e = kDpMinExponent + 1;
}
}
DiyFp operator-(const DiyFp &rhs) const
{
assert(e == rhs.e);
assert(f >= rhs.f);
return DiyFp(f - rhs.f, e);
}
DiyFp operator*(const DiyFp &rhs) const
{
#if defined(_MSC_VER) && defined(_M_AMD64)
uint64_t h;
uint64_t l = _umul128(f, rhs.f, &h);
if (l & (uint64_t(1) << 63)) // rounding
h++;
return DiyFp(h, e + rhs.e + 64);
#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)
unsigned __int128 p =
static_cast<unsigned __int128>(f) * static_cast<unsigned __int128>(rhs.f);
uint64_t h = p >> 64;
uint64_t l = static_cast<uint64_t>(p);
if (l & (uint64_t(1) << 63)) // rounding
h++;
return DiyFp(h, e + rhs.e + 64);
#else
const uint64_t M32 = 0xFFFFFFFF;
const uint64_t a = f >> 32;
const uint64_t b = f & M32;
const uint64_t c = rhs.f >> 32;
const uint64_t d = rhs.f & M32;
const uint64_t ac = a * c;
const uint64_t bc = b * c;
const uint64_t ad = a * d;
const uint64_t bd = b * d;
uint64_t tmp = (bd >> 32) + (ad & M32) + (bc & M32);
tmp += 1U << 31; /// mult_round
return DiyFp(ac + (ad >> 32) + (bc >> 32) + (tmp >> 32), e + rhs.e + 64);
#endif
}
DiyFp Normalize() const
{
#if defined(_MSC_VER) && defined(_M_AMD64)
unsigned long index;
_BitScanReverse64(&index, f);
return DiyFp(f << (63 - index), e - (63 - index));
#elif defined(__GNUC__)
int s = __builtin_clzll(f);
return DiyFp(f << s, e - s);
#else
DiyFp res = *this;
while (!(res.f & kDpHiddenBit))
{
res.f <<= 1;
res.e--;
}
res.f <<= (kDiySignificandSize - kDpSignificandSize - 1);
res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 1);
return res;
#endif
}
DiyFp NormalizeBoundary() const
{
#if defined(_MSC_VER) && defined(_M_AMD64)
unsigned long index;
_BitScanReverse64(&index, f);
return DiyFp(f << (63 - index), e - (63 - index));
#else
DiyFp res = *this;
while (!(res.f & (kDpHiddenBit << 1)))
{
res.f <<= 1;
res.e--;
}
res.f <<= (kDiySignificandSize - kDpSignificandSize - 2);
res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 2);
return res;
#endif
}
void NormalizedBoundaries(DiyFp *minus, DiyFp *plus) const
{
DiyFp pl = DiyFp((f << 1) + 1, e - 1).NormalizeBoundary();
DiyFp mi = (f == kDpHiddenBit) ? DiyFp((f << 2) - 1, e - 2) : DiyFp((f << 1) - 1, e - 1);
mi.f <<= mi.e - pl.e;
mi.e = pl.e;
*plus = pl;
*minus = mi;
}
static const int kDiySignificandSize = 64;
static const int kDpSignificandSize = 52;
static const int kDpExponentBias = 0x3FF + kDpSignificandSize;
static const int kDpMinExponent = -kDpExponentBias;
static const uint64_t kDpExponentMask = UINT64_C2(0x7FF00000, 0x00000000);
static const uint64_t kDpSignificandMask = UINT64_C2(0x000FFFFF, 0xFFFFFFFF);
static const uint64_t kDpHiddenBit = UINT64_C2(0x00100000, 0x00000000);
uint64_t f;
int e;
};
inline DiyFp GetCachedPower(int e, int *K)
{
// 10^-348, 10^-340, ..., 10^340
static const uint64_t kCachedPowers_F[] = {
UINT64_C2(0xfa8fd5a0, 0x081c0288), UINT64_C2(0xbaaee17f, 0xa23ebf76),
UINT64_C2(0x8b16fb20, 0x3055ac76), UINT64_C2(0xcf42894a, 0x5dce35ea),
UINT64_C2(0x9a6bb0aa, 0x55653b2d), UINT64_C2(0xe61acf03, 0x3d1a45df),
UINT64_C2(0xab70fe17, 0xc79ac6ca), UINT64_C2(0xff77b1fc, 0xbebcdc4f),
UINT64_C2(0xbe5691ef, 0x416bd60c), UINT64_C2(0x8dd01fad, 0x907ffc3c),
UINT64_C2(0xd3515c28, 0x31559a83), UINT64_C2(0x9d71ac8f, 0xada6c9b5),
UINT64_C2(0xea9c2277, 0x23ee8bcb), UINT64_C2(0xaecc4991, 0x4078536d),
UINT64_C2(0x823c1279, 0x5db6ce57), UINT64_C2(0xc2109436, 0x4dfb5637),
UINT64_C2(0x9096ea6f, 0x3848984f), UINT64_C2(0xd77485cb, 0x25823ac7),
UINT64_C2(0xa086cfcd, 0x97bf97f4), UINT64_C2(0xef340a98, 0x172aace5),
UINT64_C2(0xb23867fb, 0x2a35b28e), UINT64_C2(0x84c8d4df, 0xd2c63f3b),
UINT64_C2(0xc5dd4427, 0x1ad3cdba), UINT64_C2(0x936b9fce, 0xbb25c996),
UINT64_C2(0xdbac6c24, 0x7d62a584), UINT64_C2(0xa3ab6658, 0x0d5fdaf6),
UINT64_C2(0xf3e2f893, 0xdec3f126), UINT64_C2(0xb5b5ada8, 0xaaff80b8),
UINT64_C2(0x87625f05, 0x6c7c4a8b), UINT64_C2(0xc9bcff60, 0x34c13053),
UINT64_C2(0x964e858c, 0x91ba2655), UINT64_C2(0xdff97724, 0x70297ebd),
UINT64_C2(0xa6dfbd9f, 0xb8e5b88f), UINT64_C2(0xf8a95fcf, 0x88747d94),
UINT64_C2(0xb9447093, 0x8fa89bcf), UINT64_C2(0x8a08f0f8, 0xbf0f156b),
UINT64_C2(0xcdb02555, 0x653131b6), UINT64_C2(0x993fe2c6, 0xd07b7fac),
UINT64_C2(0xe45c10c4, 0x2a2b3b06), UINT64_C2(0xaa242499, 0x697392d3),
UINT64_C2(0xfd87b5f2, 0x8300ca0e), UINT64_C2(0xbce50864, 0x92111aeb),
UINT64_C2(0x8cbccc09, 0x6f5088cc), UINT64_C2(0xd1b71758, 0xe219652c),
UINT64_C2(0x9c400000, 0x00000000), UINT64_C2(0xe8d4a510, 0x00000000),
UINT64_C2(0xad78ebc5, 0xac620000), UINT64_C2(0x813f3978, 0xf8940984),
UINT64_C2(0xc097ce7b, 0xc90715b3), UINT64_C2(0x8f7e32ce, 0x7bea5c70),
UINT64_C2(0xd5d238a4, 0xabe98068), UINT64_C2(0x9f4f2726, 0x179a2245),
UINT64_C2(0xed63a231, 0xd4c4fb27), UINT64_C2(0xb0de6538, 0x8cc8ada8),
UINT64_C2(0x83c7088e, 0x1aab65db), UINT64_C2(0xc45d1df9, 0x42711d9a),
UINT64_C2(0x924d692c, 0xa61be758), UINT64_C2(0xda01ee64, 0x1a708dea),
UINT64_C2(0xa26da399, 0x9aef774a), UINT64_C2(0xf209787b, 0xb47d6b85),
UINT64_C2(0xb454e4a1, 0x79dd1877), UINT64_C2(0x865b8692, 0x5b9bc5c2),
UINT64_C2(0xc83553c5, 0xc8965d3d), UINT64_C2(0x952ab45c, 0xfa97a0b3),
UINT64_C2(0xde469fbd, 0x99a05fe3), UINT64_C2(0xa59bc234, 0xdb398c25),
UINT64_C2(0xf6c69a72, 0xa3989f5c), UINT64_C2(0xb7dcbf53, 0x54e9bece),
UINT64_C2(0x88fcf317, 0xf22241e2), UINT64_C2(0xcc20ce9b, 0xd35c78a5),
UINT64_C2(0x98165af3, 0x7b2153df), UINT64_C2(0xe2a0b5dc, 0x971f303a),
UINT64_C2(0xa8d9d153, 0x5ce3b396), UINT64_C2(0xfb9b7cd9, 0xa4a7443c),
UINT64_C2(0xbb764c4c, 0xa7a44410), UINT64_C2(0x8bab8eef, 0xb6409c1a),
UINT64_C2(0xd01fef10, 0xa657842c), UINT64_C2(0x9b10a4e5, 0xe9913129),
UINT64_C2(0xe7109bfb, 0xa19c0c9d), UINT64_C2(0xac2820d9, 0x623bf429),
UINT64_C2(0x80444b5e, 0x7aa7cf85), UINT64_C2(0xbf21e440, 0x03acdd2d),
UINT64_C2(0x8e679c2f, 0x5e44ff8f), UINT64_C2(0xd433179d, 0x9c8cb841),
UINT64_C2(0x9e19db92, 0xb4e31ba9), UINT64_C2(0xeb96bf6e, 0xbadf77d9),
UINT64_C2(0xaf87023b, 0x9bf0ee6b)};
static const int16_t kCachedPowers_E[] = {
-1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, -954, -927, -901,
-874, -847, -821, -794, -768, -741, -715, -688, -661, -635, -608, -582, -555,
-529, -502, -475, -449, -422, -396, -369, -343, -316, -289, -263, -236, -210,
-183, -157, -130, -103, -77, -50, -24, 3, 30, 56, 83, 109, 136,
162, 189, 216, 242, 269, 295, 322, 348, 375, 402, 428, 455, 481,
508, 534, 561, 588, 614, 641, 667, 694, 720, 747, 774, 800, 827,
853, 880, 907, 933, 960, 986, 1013, 1039, 1066};
// int k = static_cast<int>(ceil((-61 - e) * 0.30102999566398114)) + 374;
double dk =
(-61 - e) * 0.30102999566398114 + 347; // dk must be positive, so can do ceiling in positive
int k = static_cast<int>(dk);
if (k != dk)
k++;
unsigned index = static_cast<unsigned>((k >> 3) + 1);
*K = -(-348 + static_cast<int>(index << 3)); // decimal exponent no need lookup table
assert(index < sizeof(kCachedPowers_F) / sizeof(kCachedPowers_F[0]));
return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]);
}
inline void
GrisuRound(char *buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w)
{
while (rest < wp_w && delta - rest >= ten_kappa && (rest + ten_kappa < wp_w || /// closer
wp_w - rest > rest + ten_kappa - wp_w))
{
buffer[len - 1]--;
rest += ten_kappa;
}
}
inline unsigned CountDecimalDigit32(uint32_t n)
{
// Simple pure C++ implementation was faster than __builtin_clz version in this situation.
if (n < 10)
return 1;
if (n < 100)
return 2;
if (n < 1000)
return 3;
if (n < 10000)
return 4;
if (n < 100000)
return 5;
if (n < 1000000)
return 6;
if (n < 10000000)
return 7;
if (n < 100000000)
return 8;
if (n < 1000000000)
return 9;
return 10;
}
inline void
DigitGen(const DiyFp &W, const DiyFp &Mp, uint64_t delta, char *buffer, int *len, int *K)
{
static const uint32_t kPow10[] = {
1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000};
const DiyFp one(uint64_t(1) << -Mp.e, Mp.e);
const DiyFp wp_w = Mp - W;
uint32_t p1 = static_cast<uint32_t>(Mp.f >> -one.e);
uint64_t p2 = Mp.f & (one.f - 1);
int kappa = static_cast<int>(CountDecimalDigit32(p1));
*len = 0;
while (kappa > 0)
{
uint32_t d;
switch (kappa)
{
case 10:
d = p1 / 1000000000;
p1 %= 1000000000;
break;
case 9:
d = p1 / 100000000;
p1 %= 100000000;
break;
case 8:
d = p1 / 10000000;
p1 %= 10000000;
break;
case 7:
d = p1 / 1000000;
p1 %= 1000000;
break;
case 6:
d = p1 / 100000;
p1 %= 100000;
break;
case 5:
d = p1 / 10000;
p1 %= 10000;
break;
case 4:
d = p1 / 1000;
p1 %= 1000;
break;
case 3:
d = p1 / 100;
p1 %= 100;
break;
case 2:
d = p1 / 10;
p1 %= 10;
break;
case 1:
d = p1;
p1 = 0;
break;
default:
#if defined(_MSC_VER)
__assume(0);
#elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
__builtin_unreachable();
#else
d = 0;
#endif
}
if (d || *len)
buffer[(*len)++] = '0' + static_cast<char>(d);
kappa--;
uint64_t tmp = (static_cast<uint64_t>(p1) << -one.e) + p2;
if (tmp <= delta)
{
*K += kappa;
GrisuRound(
buffer, *len, delta, tmp, static_cast<uint64_t>(kPow10[kappa]) << -one.e, wp_w.f);
return;
}
}
// kappa = 0
for (;;)
{
p2 *= 10;
delta *= 10;
char d = static_cast<char>(p2 >> -one.e);
if (d || *len)
buffer[(*len)++] = '0' + d;
p2 &= one.f - 1;
kappa--;
if (p2 < delta)
{
*K += kappa;
GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * kPow10[-kappa]);
return;
}
}
}
inline void Grisu2(double value, char *buffer, int *length, int *K)
{
const DiyFp v(value);
DiyFp w_m, w_p;
v.NormalizedBoundaries(&w_m, &w_p);
const DiyFp c_mk = GetCachedPower(w_p.e, K);
const DiyFp W = v.Normalize() * c_mk;
DiyFp Wp = w_p * c_mk;
DiyFp Wm = w_m * c_mk;
Wm.f++;
Wp.f--;
DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K);
}
inline const char *GetDigitsLut()
{
static const char cDigitsLut[200] = {
'0', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5', '0', '6', '0', '7', '0',
'8', '0', '9', '1', '0', '1', '1', '1', '2', '1', '3', '1', '4', '1', '5', '1', '6',
'1', '7', '1', '8', '1', '9', '2', '0', '2', '1', '2', '2', '2', '3', '2', '4', '2',
'5', '2', '6', '2', '7', '2', '8', '2', '9', '3', '0', '3', '1', '3', '2', '3', '3',
'3', '4', '3', '5', '3', '6', '3', '7', '3', '8', '3', '9', '4', '0', '4', '1', '4',
'2', '4', '3', '4', '4', '4', '5', '4', '6', '4', '7', '4', '8', '4', '9', '5', '0',
'5', '1', '5', '2', '5', '3', '5', '4', '5', '5', '5', '6', '5', '7', '5', '8', '5',
'9', '6', '0', '6', '1', '6', '2', '6', '3', '6', '4', '6', '5', '6', '6', '6', '7',
'6', '8', '6', '9', '7', '0', '7', '1', '7', '2', '7', '3', '7', '4', '7', '5', '7',
'6', '7', '7', '7', '8', '7', '9', '8', '0', '8', '1', '8', '2', '8', '3', '8', '4',
'8', '5', '8', '6', '8', '7', '8', '8', '8', '9', '9', '0', '9', '1', '9', '2', '9',
'3', '9', '4', '9', '5', '9', '6', '9', '7', '9', '8', '9', '9'};
return cDigitsLut;
}
inline void WriteExponent(int K, char *buffer)
{
if (K < 0)
{
*buffer++ = '-';
K = -K;
}
if (K >= 100)
{
*buffer++ = '0' + static_cast<char>(K / 100);
K %= 100;
const char *d = GetDigitsLut() + K * 2;
*buffer++ = d[0];
*buffer++ = d[1];
}
else if (K >= 10)
{
const char *d = GetDigitsLut() + K * 2;
*buffer++ = d[0];
*buffer++ = d[1];
}
else
*buffer++ = '0' + static_cast<char>(K);
*buffer = '\0';
}
inline void Prettify(char *buffer, int length, int k)
{
const int kk = length + k; // 10^(kk-1) <= v < 10^kk
if (length <= kk && kk <= 21)
{
// 1234e7 -> 12340000000
for (int i = length; i < kk; i++)
buffer[i] = '0';
buffer[kk] = '.';
buffer[kk + 1] = '0';
buffer[kk + 2] = '\0';
}
else if (0 < kk && kk <= 21)
{
// 1234e-2 -> 12.34
memmove(&buffer[kk + 1], &buffer[kk], length - kk);
buffer[kk] = '.';
buffer[length + 1] = '\0';
}
else if (-6 < kk && kk <= 0)
{
// 1234e-6 -> 0.001234
const int offset = 2 - kk;
memmove(&buffer[offset], &buffer[0], length);
buffer[0] = '0';
buffer[1] = '.';
for (int i = 2; i < offset; i++)
buffer[i] = '0';
buffer[length + offset] = '\0';
}
else if (length == 1)
{
// 1e30
buffer[1] = 'e';
WriteExponent(kk - 1, &buffer[2]);
}
else
{
// 1234e30 -> 1.234e33
memmove(&buffer[2], &buffer[1], length - 1);
buffer[1] = '.';
buffer[length + 1] = 'e';
WriteExponent(kk - 1, &buffer[0 + length + 2]);
}
}
inline void dtoa_milo(double value, char *buffer)
{
// Not handling NaN and inf
assert(!isnan(value));
assert(!isinf(value));
if (value == 0)
{
buffer[0] = '0';
buffer[1] = '.';
buffer[2] = '0';
buffer[3] = '\0';
}
else
{
if (value < 0)
{
*buffer++ = '-';
value = -value;
}
int length, K;
Grisu2(value, buffer, &length, &K);
Prettify(buffer, length, K);
}
}
} // namespace ieee754
} // namespace util
} // namespace osrm
#endif // IEEE754_HPP
+31 -2
View File
@@ -5,6 +5,7 @@
#define JSON_RENDERER_HPP
#include "util/cast.hpp"
#include "util/ieee754.hpp"
#include "util/string_util.hpp"
#include "osrm/json_container.hpp"
@@ -21,6 +22,11 @@ namespace util
namespace json
{
namespace
{
constexpr int MAX_FLOAT_STRING_LENGTH = 256;
}
struct Renderer
{
explicit Renderer(std::ostream &_out) : out(_out) {}
@@ -34,8 +40,31 @@ struct Renderer
void operator()(const Number &number) const
{
out.precision(10);
out << number.value;
char buffer[MAX_FLOAT_STRING_LENGTH] = {'\0'};
ieee754::dtoa_milo(number.value, buffer);
// Trucate to 10 decimal places
int pos = 0;
int decimalpos = 0;
while (decimalpos == 0 && pos < MAX_FLOAT_STRING_LENGTH && buffer[pos] != 0)
{
if (buffer[pos] == '.')
{
decimalpos = pos;
break;
}
++pos;
}
while (pos < MAX_FLOAT_STRING_LENGTH && buffer[pos] != 0)
{
if (pos - decimalpos == 10)
{
buffer[pos] = '\0';
break;
}
++pos;
}
out << buffer;
}
void operator()(const Object &object) const
+17 -16
View File
@@ -15,14 +15,14 @@ namespace util
namespace detail
{
template <typename T, typename RegionT>
util::vector_view<T> mmapFile(const boost::filesystem::path &file, RegionT &region)
template <typename T, typename MmapContainerT>
util::vector_view<T> mmapFile(const boost::filesystem::path &file, MmapContainerT &mmap_container)
{
try
{
region.open(file);
std::size_t num_objects = region.size() / sizeof(T);
auto data_ptr = region.data();
mmap_container.open(file);
std::size_t num_objects = mmap_container.size() / sizeof(T);
auto data_ptr = mmap_container.data();
BOOST_ASSERT(reinterpret_cast<uintptr_t>(data_ptr) % alignof(T) == 0);
return util::vector_view<T>(reinterpret_cast<T *>(data_ptr), num_objects);
}
@@ -34,9 +34,10 @@ util::vector_view<T> mmapFile(const boost::filesystem::path &file, RegionT &regi
}
}
template <typename T, typename RegionT>
util::vector_view<T>
mmapFile(const boost::filesystem::path &file, RegionT &region, const std::size_t size)
template <typename T, typename MmapContainerT>
util::vector_view<T> mmapFile(const boost::filesystem::path &file,
MmapContainerT &mmap_container,
const std::size_t size)
{
try
{
@@ -45,10 +46,10 @@ mmapFile(const boost::filesystem::path &file, RegionT &region, const std::size_t
params.path = file.string();
params.flags = boost::iostreams::mapped_file::readwrite;
params.new_file_size = size;
region.open(params);
mmap_container.open(params);
std::size_t num_objects = size / sizeof(T);
auto data_ptr = region.data();
auto data_ptr = mmap_container.data();
BOOST_ASSERT(reinterpret_cast<uintptr_t>(data_ptr) % alignof(T) == 0);
return util::vector_view<T>(reinterpret_cast<T *>(data_ptr), num_objects);
}
@@ -63,24 +64,24 @@ mmapFile(const boost::filesystem::path &file, RegionT &region, const std::size_t
template <typename T>
util::vector_view<const T> mmapFile(const boost::filesystem::path &file,
boost::iostreams::mapped_file_source &region)
boost::iostreams::mapped_file_source &mmap_container)
{
return detail::mmapFile<const T>(file, region);
return detail::mmapFile<const T>(file, mmap_container);
}
template <typename T>
util::vector_view<T> mmapFile(const boost::filesystem::path &file,
boost::iostreams::mapped_file &region)
boost::iostreams::mapped_file &mmap_container)
{
return detail::mmapFile<T>(file, region);
return detail::mmapFile<T>(file, mmap_container);
}
template <typename T>
util::vector_view<T> mmapFile(const boost::filesystem::path &file,
boost::iostreams::mapped_file &region,
boost::iostreams::mapped_file &mmap_container,
std::size_t size)
{
return detail::mmapFile<T>(file, region, size);
return detail::mmapFile<T>(file, mmap_container, size);
}
}
}
+10 -4
View File
@@ -9,6 +9,7 @@
#include <tbb/parallel_sort.h>
#include <iostream>
#include <memory>
#include <utility>
@@ -20,24 +21,27 @@ namespace util
struct NodeBasedEdgeData
{
NodeBasedEdgeData()
: weight(INVALID_EDGE_WEIGHT), duration(INVALID_EDGE_WEIGHT), geometry_id({0, false}),
reversed(false), annotation_data(-1)
: weight(INVALID_EDGE_WEIGHT), duration(INVALID_EDGE_WEIGHT),
distance(INVALID_EDGE_DISTANCE), geometry_id({0, false}), reversed(false),
annotation_data(-1)
{
}
NodeBasedEdgeData(EdgeWeight weight,
EdgeWeight duration,
EdgeDistance distance,
GeometryID geometry_id,
bool reversed,
extractor::NodeBasedEdgeClassification flags,
AnnotationID annotation_data)
: weight(weight), duration(duration), geometry_id(geometry_id), reversed(reversed),
flags(flags), annotation_data(annotation_data)
: weight(weight), duration(duration), distance(distance), geometry_id(geometry_id),
reversed(reversed), flags(flags), annotation_data(annotation_data)
{
}
EdgeWeight weight;
EdgeWeight duration;
EdgeDistance distance;
GeometryID geometry_id;
bool reversed : 1;
extractor::NodeBasedEdgeClassification flags;
@@ -80,11 +84,13 @@ NodeBasedDynamicGraphFromEdges(NodeID number_of_nodes,
const extractor::NodeBasedEdge &input_edge) {
output_edge.data.weight = input_edge.weight;
output_edge.data.duration = input_edge.duration;
output_edge.data.distance = input_edge.distance;
output_edge.data.flags = input_edge.flags;
output_edge.data.annotation_data = input_edge.annotation_data;
BOOST_ASSERT(output_edge.data.weight > 0);
BOOST_ASSERT(output_edge.data.duration > 0);
BOOST_ASSERT(output_edge.data.distance >= 0);
});
tbb::parallel_sort(edges_list.begin(), edges_list.end());
+1
View File
@@ -113,6 +113,7 @@ static const SegmentWeight MAX_SEGMENT_WEIGHT = INVALID_SEGMENT_WEIGHT - 1;
static const SegmentDuration MAX_SEGMENT_DURATION = INVALID_SEGMENT_DURATION - 1;
static const EdgeWeight INVALID_EDGE_WEIGHT = std::numeric_limits<EdgeWeight>::max();
static const EdgeDuration MAXIMAL_EDGE_DURATION = std::numeric_limits<EdgeDuration>::max();
static const EdgeDistance MAXIMAL_EDGE_DISTANCE = std::numeric_limits<EdgeDistance>::max();
static const TurnPenalty INVALID_TURN_PENALTY = std::numeric_limits<TurnPenalty>::max();
static const EdgeDistance INVALID_EDGE_DISTANCE = std::numeric_limits<EdgeDistance>::max();
+15
View File
@@ -195,7 +195,10 @@ template <> class vector_view<bool>
{
BOOST_ASSERT_MSG(index < m_size, "invalid size");
const std::size_t bucket = index / WORD_BITS;
// Note: ordering of bits here should match packBits in storage/serialization.hpp
// so that directly mmap-ing data is possible
const auto offset = index % WORD_BITS;
BOOST_ASSERT(WORD_BITS > offset);
return m_ptr[bucket] & (static_cast<Word>(1) << offset);
}
@@ -224,11 +227,23 @@ template <> class vector_view<bool>
{
BOOST_ASSERT(index < m_size);
const auto bucket = index / WORD_BITS;
// Note: ordering of bits here should match packBits in storage/serialization.hpp
// so that directly mmap-ing data is possible
const auto offset = index % WORD_BITS;
BOOST_ASSERT(WORD_BITS > offset);
return reference{m_ptr + bucket, static_cast<Word>(1) << offset};
}
template <typename T> friend void swap(vector_view<T> &, vector_view<T> &) noexcept;
friend std::ostream &operator<<(std::ostream &os, const vector_view<bool> &rhs)
{
for (std::size_t i = 0; i < rhs.size(); ++i)
{
os << (i > 0 ? " " : "") << rhs.at(i);
}
return os;
}
};
// Both vector_view<T> and the vector_view<bool> specializations share this impl.
+4483 -636
View File
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -1,11 +1,11 @@
{
"name": "osrm",
"version": "5.18.0-latest.1",
"version": "5.20.0-rc.5",
"private": false,
"description": "The Open Source Routing Machine is a high performance routing engine written in C++14 designed to run on OpenStreetMap data.",
"dependencies": {
"mkdirp": "^0.5.1",
"nan": "^2.6.2",
"nan": "^2.11.1",
"node-cmake": "^2.3.2",
"node-pre-gyp": "^0.6.36",
"rimraf": "^2.5.4"
@@ -18,7 +18,7 @@
},
"scripts": {
"lint": "node ./node_modules/eslint/bin/eslint.js -c ./.eslintrc features/step_definitions/ features/support/",
"test": "npm run lint && node ./node_modules/cucumber/bin/cucumber.js features/ -p verify && node ./node_modules/cucumber/bin/cucumber.js features/ -p mld",
"test": "npm run lint && node ./node_modules/cucumber/bin/cucumber.js features/ -p verify && node ./node_modules/cucumber/bin/cucumber.js features/ -p verify -m mmap && node ./node_modules/cucumber/bin/cucumber.js features/ -p mld && node ./node_modules/cucumber/bin/cucumber.js features/ -p mld -m mmap",
"clean": "rm -rf test/cache",
"docs": "./scripts/build_api_docs.sh",
"install": "node-pre-gyp install --fallback-to-build=false || ./scripts/node_install.sh",
+6 -2
View File
@@ -6,8 +6,12 @@ var fs = require('fs');
var name = process.argv[2];
var cmd = process.argv.slice(3).join(' ');
var start = Date.now();
exec(cmd, (err) => {
if (err) return console.log(err);
exec(cmd, (err, stdout, stderr) => {
if (err) {
console.log(stdout);
console.log(stderr);
return process.exit(err.code);
}
var stop = +new Date();
var time = (stop - start) / 1000.;
fs.appendFileSync('/tmp/osrm.timings', `${name}\t${time}`, 'utf-8');
+4
View File
@@ -215,6 +215,7 @@ void ContractNode(ContractorThreadData *data,
target,
path_weight,
in_data.duration + out_data.duration,
in_data.distance + out_data.distance,
out_data.originalEdges + in_data.originalEdges,
node,
SHORTCUT_ARC,
@@ -225,6 +226,7 @@ void ContractNode(ContractorThreadData *data,
source,
path_weight,
in_data.duration + out_data.duration,
in_data.distance + out_data.distance,
out_data.originalEdges + in_data.originalEdges,
node,
SHORTCUT_ARC,
@@ -280,6 +282,7 @@ void ContractNode(ContractorThreadData *data,
target,
path_weight,
in_data.duration + out_data.duration,
in_data.distance + out_data.distance,
out_data.originalEdges + in_data.originalEdges,
node,
SHORTCUT_ARC,
@@ -290,6 +293,7 @@ void ContractNode(ContractorThreadData *data,
source,
path_weight,
in_data.duration + out_data.duration,
in_data.distance + out_data.distance,
out_data.originalEdges + in_data.originalEdges,
node,
SHORTCUT_ARC,
+10 -4
View File
@@ -76,6 +76,7 @@ auto LoadAndUpdateEdgeExpandedGraph(const CustomizationConfig &config,
const partitioner::MultiLevelPartition &mlp,
std::vector<EdgeWeight> &node_weights,
std::vector<EdgeDuration> &node_durations,
std::vector<EdgeDistance> &node_distances,
std::uint32_t &connectivity_checksum)
{
updater::Updater updater(config.updater_config);
@@ -84,6 +85,8 @@ auto LoadAndUpdateEdgeExpandedGraph(const CustomizationConfig &config,
EdgeID num_nodes = updater.LoadAndUpdateEdgeExpandedGraph(
edge_based_edge_list, node_weights, node_durations, connectivity_checksum);
extractor::files::readEdgeBasedNodeDistances(config.GetPath(".osrm.enw"), node_distances);
auto directed = partitioner::splitBidirectionalEdges(edge_based_edge_list);
auto tidied = partitioner::prepareEdgesForUsageInGraph<
@@ -124,10 +127,11 @@ int Customizer::Run(const CustomizationConfig &config)
partitioner::files::readPartition(config.GetPath(".osrm.partition"), mlp);
std::vector<EdgeWeight> node_weights;
std::vector<EdgeDuration> node_durations; // TODO: to be removed later
std::vector<EdgeDuration> node_durations; // TODO: remove when durations are optional
std::vector<EdgeDistance> node_distances; // TODO: remove when distances are optional
std::uint32_t connectivity_checksum = 0;
auto graph = LoadAndUpdateEdgeExpandedGraph(
config, mlp, node_weights, node_durations, connectivity_checksum);
config, mlp, node_weights, node_durations, node_distances, connectivity_checksum);
BOOST_ASSERT(graph.GetNumberOfNodes() == node_weights.size());
std::for_each(node_weights.begin(), node_weights.end(), [](auto &w) { w &= 0x7fffffff; });
util::Log() << "Loaded edge based graph: " << graph.GetNumberOfEdges() << " edges, "
@@ -166,8 +170,10 @@ int Customizer::Run(const CustomizationConfig &config)
util::Log() << "MLD customization writing took " << TIMER_SEC(writing_mld_data) << " seconds";
TIMER_START(writing_graph);
MultiLevelEdgeBasedGraph shaved_graph{
std::move(graph), std::move(node_weights), std::move(node_durations)};
MultiLevelEdgeBasedGraph shaved_graph{std::move(graph),
std::move(node_weights),
std::move(node_durations),
std::move(node_distances)};
customizer::files::writeGraph(
config.GetPath(".osrm.mldgr"), shaved_graph, connectivity_checksum);
TIMER_STOP(writing_graph);
+37 -32
View File
@@ -1,5 +1,6 @@
#include "engine/datafacade/mmap_memory_allocator.hpp"
#include "storage/block.hpp"
#include "storage/io.hpp"
#include "storage/serialization.hpp"
#include "storage/storage.hpp"
@@ -7,7 +8,7 @@
#include "util/log.hpp"
#include "util/mmap_file.hpp"
#include "boost/assert.hpp"
#include <boost/assert.hpp>
namespace osrm
{
@@ -16,46 +17,50 @@ namespace engine
namespace datafacade
{
MMapMemoryAllocator::MMapMemoryAllocator(const storage::StorageConfig &config,
const boost::filesystem::path &memory_file)
MMapMemoryAllocator::MMapMemoryAllocator(const storage::StorageConfig &config)
{
storage::Storage storage(config);
std::vector<storage::SharedDataIndex::AllocatedRegion> allocated_regions;
if (!boost::filesystem::exists(memory_file))
{
storage::DataLayout initial_layout;
storage.PopulateStaticLayout(initial_layout);
storage.PopulateUpdatableLayout(initial_layout);
std::unique_ptr<storage::BaseDataLayout> fake_layout =
std::make_unique<storage::TarDataLayout>();
auto data_size = initial_layout.GetSizeOfLayout();
// Convert the boost::filesystem::path object into a plain string
// that's stored as a member of this allocator object
rtree_filename = storage.PopulateLayoutWithRTree(*fake_layout);
storage::io::BufferWriter writer;
storage::serialization::write(writer, initial_layout);
auto encoded_layout = writer.GetBuffer();
auto total_size = data_size + encoded_layout.size();
mapped_memory = util::mmapFile<char>(memory_file, mapped_memory_file, total_size);
std::copy(encoded_layout.begin(), encoded_layout.end(), mapped_memory.data());
index = storage::SharedDataIndex(
{{mapped_memory.data() + encoded_layout.size(), std::move(initial_layout)}});
storage.PopulateStaticData(index);
storage.PopulateUpdatableData(index);
// Now, we add one more AllocatedRegion, with it's start address as the start
// of the rtree_filename string we've saved. In the fake_layout, we've
// stated that the data is at offset 0, which is where the string starts
// at it's own memory address.
// The syntax &(rtree_filename[0]) gets the memory address of the first char.
// We can't use the convenient `.data()` or `.c_str()` methods, because
// prior to C++17 (which we're not using), those return a `const char *`,
// which isn't compatible with the `char *` that AllocatedRegion expects
// for it's memory_ptr
allocated_regions.push_back({&(rtree_filename[0]), std::move(fake_layout)});
}
else
auto files = storage.GetStaticFiles();
auto updatable_files = storage.GetUpdatableFiles();
files.insert(files.end(), updatable_files.begin(), updatable_files.end());
for (const auto &file : files)
{
mapped_memory = util::mmapFile<char>(memory_file, mapped_memory_file);
storage::DataLayout layout;
storage::io::BufferReader reader(mapped_memory.data(), mapped_memory.size());
storage::serialization::read(reader, layout);
auto layout_size = reader.GetPosition();
index = storage::SharedDataIndex({{mapped_memory.data() + layout_size, std::move(layout)}});
if (boost::filesystem::exists(file.second))
{
std::unique_ptr<storage::BaseDataLayout> layout =
std::make_unique<storage::TarDataLayout>();
boost::iostreams::mapped_file mapped_memory_file;
util::mmapFile<char>(file.second, mapped_memory_file);
mapped_memory_files.push_back(std::move(mapped_memory_file));
storage::populateLayoutFromFile(file.second, *layout);
allocated_regions.push_back({mapped_memory_file.data(), std::move(layout)});
}
}
index = storage::SharedDataIndex{std::move(allocated_regions)};
}
MMapMemoryAllocator::~MMapMemoryAllocator() {}
@@ -15,14 +15,20 @@ ProcessMemoryAllocator::ProcessMemoryAllocator(const storage::StorageConfig &con
storage::Storage storage(config);
// Calculate the layout/size of the memory block
storage::DataLayout layout;
storage.PopulateStaticLayout(layout);
storage.PopulateUpdatableLayout(layout);
auto static_files = storage.GetStaticFiles();
auto updatable_files = storage.GetUpdatableFiles();
std::unique_ptr<storage::BaseDataLayout> layout =
std::make_unique<storage::ContiguousDataLayout>();
storage.PopulateLayoutWithRTree(*layout);
storage.PopulateLayout(*layout, static_files);
storage.PopulateLayout(*layout, updatable_files);
// Allocate the memory block, then load data from files into it
internal_memory = std::make_unique<char[]>(layout.GetSizeOfLayout());
internal_memory = std::make_unique<char[]>(layout->GetSizeOfLayout());
index = storage::SharedDataIndex({{internal_memory.get(), std::move(layout)}});
std::vector<storage::SharedDataIndex::AllocatedRegion> regions;
regions.push_back({internal_memory.get(), std::move(layout)});
index = {std::move(regions)};
storage.PopulateStaticData(index);
storage.PopulateUpdatableData(index);
@@ -25,8 +25,9 @@ SharedMemoryAllocator::SharedMemoryAllocator(
auto mem = storage::makeSharedMemory(shm_key);
storage::io::BufferReader reader(reinterpret_cast<char *>(mem->Ptr()), mem->Size());
storage::DataLayout layout;
storage::serialization::read(reader, layout);
std::unique_ptr<storage::BaseDataLayout> layout =
std::make_unique<storage::ContiguousDataLayout>();
storage::serialization::read(reader, *layout);
auto layout_size = reader.GetPosition();
regions.push_back({reinterpret_cast<char *>(mem->Ptr()) + layout_size, std::move(layout)});
+3 -1
View File
@@ -23,7 +23,9 @@ bool EngineConfig::IsValid() const
unlimited_or_more_than(max_results_nearest, 0) &&
max_alternatives >= 0;
return ((use_shared_memory && all_path_are_empty) || storage_config.IsValid()) && limits_valid;
return ((use_shared_memory && all_path_are_empty) || (use_mmap && storage_config.IsValid()) ||
storage_config.IsValid()) &&
limits_valid;
}
}
}
+37 -1
View File
@@ -4,6 +4,7 @@
#include "engine/api/table_parameters.hpp"
#include "engine/routing_algorithms/many_to_many.hpp"
#include "engine/search_engine_data.hpp"
#include "util/coordinate_calculation.hpp"
#include "util/json_container.hpp"
#include "util/string_util.hpp"
@@ -86,7 +87,7 @@ Status TablePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
bool request_duration = params.annotations & api::TableParameters::AnnotationsType::Duration;
auto result_tables_pair = algorithms.ManyToManySearch(
snapped_phantoms, params.sources, params.destinations, request_distance, request_duration);
snapped_phantoms, params.sources, params.destinations, request_distance);
if ((request_duration && result_tables_pair.first.empty()) ||
(request_distance && result_tables_pair.second.empty()))
@@ -94,6 +95,41 @@ Status TablePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
return Error("NoTable", "No table found", result);
}
// Scan table for null results - if any exist, replace with distance estimates
if (params.fallback_speed > 0)
{
for (std::size_t row = 0; row < num_sources; row++)
{
for (std::size_t column = 0; column < num_destinations; column++)
{
const auto &table_index = row * num_sources + column;
if (result_tables_pair.first[table_index] == MAXIMAL_EDGE_DURATION)
{
const auto &source =
snapped_phantoms[params.sources.empty() ? row : params.sources[row]];
const auto &destination =
snapped_phantoms[params.destinations.empty() ? column
: params.destinations[column]];
auto distance_estimate =
params.fallback_coordinate_type ==
api::TableParameters::FallbackCoordinateType::Input
? util::coordinate_calculation::fccApproximateDistance(
source.input_location, destination.input_location)
: util::coordinate_calculation::fccApproximateDistance(
source.location, destination.location);
result_tables_pair.first[table_index] =
distance_estimate / (double)params.fallback_speed;
if (!result_tables_pair.second.empty())
{
result_tables_pair.second[table_index] = distance_estimate;
}
}
}
}
}
api::TableAPI table_api{facade, params};
table_api.MakeResponse(result_tables_pair, snapped_phantoms, result);
+1 -4
View File
@@ -217,10 +217,7 @@ Status TripPlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms,
// compute the duration table of all phantom nodes
auto result_duration_table = util::DistTableWrapper<EdgeWeight>(
algorithms
.ManyToManySearch(
snapped_phantoms, {}, {}, /*requestDistance*/ false, /*requestDuration*/ true)
.first,
algorithms.ManyToManySearch(snapped_phantoms, {}, {}, /*requestDistance*/ false).first,
number_of_locations);
if (result_duration_table.size() == 0)
@@ -90,7 +90,7 @@ void alternativeRoutingStep(const DataFacade<Algorithm> &facade,
else
{
// check whether there is a loop present at the node
const auto loop_weight = getLoopWeight<false>(facade, node);
const auto loop_weight = std::get<0>(getLoopWeight<false>(facade, node));
const EdgeWeight new_weight_with_loop = new_weight + loop_weight;
if (loop_weight != INVALID_EDGE_WEIGHT &&
new_weight_with_loop <= *upper_bound_to_shortest_path_weight)
+33 -123
View File
@@ -21,18 +21,21 @@ namespace ch
inline bool addLoopWeight(const DataFacade<ch::Algorithm> &facade,
const NodeID node,
EdgeWeight &weight,
EdgeDuration &duration)
EdgeDuration &duration,
EdgeDistance &distance)
{ // Special case for CH when contractor creates a loop edge node->node
BOOST_ASSERT(weight < 0);
const auto loop_weight = ch::getLoopWeight<false>(facade, node);
if (loop_weight != INVALID_EDGE_WEIGHT)
if (std::get<0>(loop_weight) != INVALID_EDGE_WEIGHT)
{
const auto new_weight_with_loop = weight + loop_weight;
const auto new_weight_with_loop = weight + std::get<0>(loop_weight);
if (new_weight_with_loop >= 0)
{
weight = new_weight_with_loop;
duration += ch::getLoopWeight<true>(facade, node);
auto result = ch::getLoopWeight<true>(facade, node);
duration += std::get<0>(result);
distance += std::get<1>(result);
return true;
}
}
@@ -46,6 +49,7 @@ void relaxOutgoingEdges(const DataFacade<Algorithm> &facade,
const NodeID node,
const EdgeWeight weight,
const EdgeDuration duration,
const EdgeDistance distance,
typename SearchEngineData<Algorithm>::ManyToManyQueryHeap &query_heap,
const PhantomNode &)
{
@@ -63,21 +67,23 @@ void relaxOutgoingEdges(const DataFacade<Algorithm> &facade,
const auto edge_weight = data.weight;
const auto edge_duration = data.duration;
const auto edge_distance = data.distance;
BOOST_ASSERT_MSG(edge_weight > 0, "edge_weight invalid");
const auto to_weight = weight + edge_weight;
const auto to_duration = duration + edge_duration;
const auto to_distance = distance + edge_distance;
// New Node discovered -> Add to Heap + Node Info Storage
if (!query_heap.WasInserted(to))
{
query_heap.Insert(to, to_weight, {node, to_duration});
query_heap.Insert(to, to_weight, {node, to_duration, to_distance});
}
// Found a shorter Path -> Update weight and set new parent
else if (std::tie(to_weight, to_duration) <
std::tie(query_heap.GetKey(to), query_heap.GetData(to).duration))
{
query_heap.GetData(to) = {node, to_duration};
query_heap.GetData(to) = {node, to_duration, to_distance};
query_heap.DecreaseKey(to, to_weight);
}
}
@@ -91,12 +97,14 @@ void forwardRoutingStep(const DataFacade<Algorithm> &facade,
const std::vector<NodeBucket> &search_space_with_buckets,
std::vector<EdgeWeight> &weights_table,
std::vector<EdgeDuration> &durations_table,
std::vector<EdgeDistance> &distances_table,
std::vector<NodeID> &middle_nodes_table,
const PhantomNode &phantom_node)
{
const auto node = query_heap.DeleteMin();
const auto source_weight = query_heap.GetKey(node);
const auto source_duration = query_heap.GetData(node).duration;
const auto source_distance = query_heap.GetData(node).distance;
// Check if each encountered node has an entry
const auto &bucket_list = std::equal_range(search_space_with_buckets.begin(),
@@ -109,20 +117,29 @@ void forwardRoutingStep(const DataFacade<Algorithm> &facade,
const auto column_index = current_bucket.column_index;
const auto target_weight = current_bucket.weight;
const auto target_duration = current_bucket.duration;
const auto target_distance = current_bucket.distance;
auto &current_weight = weights_table[row_index * number_of_targets + column_index];
EdgeDistance nulldistance = 0;
auto &current_duration = durations_table[row_index * number_of_targets + column_index];
auto &current_distance =
distances_table.empty() ? nulldistance
: distances_table[row_index * number_of_targets + column_index];
// Check if new weight is better
auto new_weight = source_weight + target_weight;
auto new_duration = source_duration + target_duration;
auto new_distance = source_distance + target_distance;
if (new_weight < 0)
{
if (addLoopWeight(facade, node, new_weight, new_duration))
if (addLoopWeight(facade, node, new_weight, new_duration, new_distance))
{
current_weight = std::min(current_weight, new_weight);
current_duration = std::min(current_duration, new_duration);
current_distance = std::min(current_distance, new_distance);
middle_nodes_table[row_index * number_of_targets + column_index] = node;
}
}
@@ -130,12 +147,13 @@ void forwardRoutingStep(const DataFacade<Algorithm> &facade,
{
current_weight = new_weight;
current_duration = new_duration;
current_distance = new_distance;
middle_nodes_table[row_index * number_of_targets + column_index] = node;
}
}
relaxOutgoingEdges<FORWARD_DIRECTION>(
facade, node, source_weight, source_duration, query_heap, phantom_node);
facade, node, source_weight, source_duration, source_distance, query_heap, phantom_node);
}
void backwardRoutingStep(const DataFacade<Algorithm> &facade,
@@ -147,110 +165,19 @@ void backwardRoutingStep(const DataFacade<Algorithm> &facade,
const auto node = query_heap.DeleteMin();
const auto target_weight = query_heap.GetKey(node);
const auto target_duration = query_heap.GetData(node).duration;
const auto target_distance = query_heap.GetData(node).distance;
const auto parent = query_heap.GetData(node).parent;
// Store settled nodes in search space bucket
search_space_with_buckets.emplace_back(
node, parent, column_index, target_weight, target_duration);
node, parent, column_index, target_weight, target_duration, target_distance);
relaxOutgoingEdges<REVERSE_DIRECTION>(
facade, node, target_weight, target_duration, query_heap, phantom_node);
facade, node, target_weight, target_duration, target_distance, query_heap, phantom_node);
}
} // namespace ch
void retrievePackedPathFromSearchSpace(const NodeID middle_node_id,
const unsigned column_index,
const std::vector<NodeBucket> &search_space_with_buckets,
std::vector<NodeID> &packed_leg)
{
auto bucket_list = std::equal_range(search_space_with_buckets.begin(),
search_space_with_buckets.end(),
middle_node_id,
NodeBucket::ColumnCompare(column_index));
NodeID current_node_id = middle_node_id;
BOOST_ASSERT_MSG(std::distance(bucket_list.first, bucket_list.second) == 1,
"The pointers are not pointing to the same element.");
while (bucket_list.first->parent_node != current_node_id &&
bucket_list.first != search_space_with_buckets.end())
{
current_node_id = bucket_list.first->parent_node;
packed_leg.emplace_back(current_node_id);
bucket_list = std::equal_range(search_space_with_buckets.begin(),
search_space_with_buckets.end(),
current_node_id,
NodeBucket::ColumnCompare(column_index));
}
}
void calculateDistances(typename SearchEngineData<ch::Algorithm>::ManyToManyQueryHeap &query_heap,
const DataFacade<ch::Algorithm> &facade,
const std::vector<PhantomNode> &phantom_nodes,
const std::vector<std::size_t> &target_indices,
const std::size_t row_index,
const std::size_t source_index,
const PhantomNode &source_phantom,
const std::size_t number_of_targets,
const std::vector<NodeBucket> &search_space_with_buckets,
std::vector<EdgeDistance> &distances_table,
const std::vector<NodeID> &middle_nodes_table)
{
std::vector<NodeID> packed_leg;
for (auto column_index : util::irange<std::size_t>(0, number_of_targets))
{
const auto target_index = target_indices[column_index];
const auto &target_phantom = phantom_nodes[target_index];
if (source_index == target_index)
{
distances_table[row_index * number_of_targets + column_index] = 0.0;
continue;
}
NodeID middle_node_id = middle_nodes_table[row_index * number_of_targets + column_index];
if (middle_node_id == SPECIAL_NODEID) // takes care of one-ways
{
distances_table[row_index * number_of_targets + column_index] = INVALID_EDGE_DISTANCE;
continue;
}
// Step 1: Find path from source to middle node
ch::retrievePackedPathFromSingleManyToManyHeap(query_heap, middle_node_id, packed_leg);
std::reverse(packed_leg.begin(), packed_leg.end());
packed_leg.push_back(middle_node_id);
// Step 2: Find path from middle to target node
retrievePackedPathFromSearchSpace(
middle_node_id, column_index, search_space_with_buckets, packed_leg);
if (packed_leg.size() == 1 && (needsLoopForward(source_phantom, target_phantom) ||
needsLoopBackwards(source_phantom, target_phantom)))
{
auto weight = ch::getLoopWeight<false>(facade, packed_leg.front());
if (weight != INVALID_EDGE_WEIGHT)
packed_leg.push_back(packed_leg.front());
}
if (!packed_leg.empty())
{
EdgeDistance annotation =
ch::calculateEBGNodeAnnotations(facade, packed_leg.begin(), packed_leg.end());
annotation = adjustPathDistanceToPhantomNodes(
packed_leg, source_phantom, target_phantom, annotation);
distances_table[row_index * number_of_targets + column_index] = annotation;
}
packed_leg.clear();
}
}
template <>
std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
manyToManySearch(SearchEngineData<ch::Algorithm> &engine_working_data,
@@ -258,18 +185,16 @@ manyToManySearch(SearchEngineData<ch::Algorithm> &engine_working_data,
const std::vector<PhantomNode> &phantom_nodes,
const std::vector<std::size_t> &source_indices,
const std::vector<std::size_t> &target_indices,
const bool calculate_distance,
const bool calculate_duration)
const bool calculate_distance)
{
(void)calculate_duration; // TODO: stub to use when computing durations become optional
const auto number_of_sources = source_indices.size();
const auto number_of_targets = target_indices.size();
const auto number_of_entries = number_of_sources * number_of_targets;
std::vector<EdgeWeight> weights_table(number_of_entries, INVALID_EDGE_WEIGHT);
std::vector<EdgeDuration> durations_table(number_of_entries, MAXIMAL_EDGE_DURATION);
std::vector<EdgeDistance> distances_table;
std::vector<EdgeDistance> distances_table(calculate_distance ? number_of_entries : 0,
MAXIMAL_EDGE_DISTANCE);
std::vector<NodeID> middle_nodes_table(number_of_entries, SPECIAL_NODEID);
std::vector<NodeBucket> search_space_with_buckets;
@@ -318,25 +243,10 @@ manyToManySearch(SearchEngineData<ch::Algorithm> &engine_working_data,
search_space_with_buckets,
weights_table,
durations_table,
distances_table,
middle_nodes_table,
source_phantom);
}
if (calculate_distance)
{
distances_table.resize(number_of_entries, INVALID_EDGE_DISTANCE);
calculateDistances(query_heap,
facade,
phantom_nodes,
target_indices,
row_index,
source_index,
source_phantom,
number_of_targets,
search_space_with_buckets,
distances_table,
middle_nodes_table);
}
}
return std::make_pair(durations_table, distances_table);
+114 -374
View File
@@ -41,6 +41,7 @@ void relaxOutgoingEdges(const DataFacade<mld::Algorithm> &facade,
const NodeID node,
const EdgeWeight weight,
const EdgeDuration duration,
const EdgeDistance distance,
typename SearchEngineData<mld::Algorithm>::ManyToManyQueryHeap &query_heap,
Args... args)
{
@@ -65,65 +66,77 @@ void relaxOutgoingEdges(const DataFacade<mld::Algorithm> &facade,
{ // Shortcuts in forward direction
auto destination = cell.GetDestinationNodes().begin();
auto shortcut_durations = cell.GetOutDuration(node);
auto shortcut_distances = cell.GetOutDistance(node);
for (auto shortcut_weight : cell.GetOutWeight(node))
{
BOOST_ASSERT(destination != cell.GetDestinationNodes().end());
BOOST_ASSERT(!shortcut_durations.empty());
BOOST_ASSERT(!shortcut_distances.empty());
const NodeID to = *destination;
if (shortcut_weight != INVALID_EDGE_WEIGHT && node != to)
{
const auto to_weight = weight + shortcut_weight;
const auto to_duration = duration + shortcut_durations.front();
const auto to_distance = distance + shortcut_distances.front();
if (!query_heap.WasInserted(to))
{
query_heap.Insert(to, to_weight, {node, true, to_duration});
query_heap.Insert(to, to_weight, {node, true, to_duration, to_distance});
}
else if (std::tie(to_weight, to_duration, node) <
else if (std::tie(to_weight, to_duration, to_distance, node) <
std::tie(query_heap.GetKey(to),
query_heap.GetData(to).duration,
query_heap.GetData(to).distance,
query_heap.GetData(to).parent))
{
query_heap.GetData(to) = {node, true, to_duration};
query_heap.GetData(to) = {node, true, to_duration, to_distance};
query_heap.DecreaseKey(to, to_weight);
}
}
++destination;
shortcut_durations.advance_begin(1);
shortcut_distances.advance_begin(1);
}
BOOST_ASSERT(shortcut_durations.empty());
BOOST_ASSERT(shortcut_distances.empty());
}
else
{ // Shortcuts in backward direction
auto source = cell.GetSourceNodes().begin();
auto shortcut_durations = cell.GetInDuration(node);
auto shortcut_distances = cell.GetInDistance(node);
for (auto shortcut_weight : cell.GetInWeight(node))
{
BOOST_ASSERT(source != cell.GetSourceNodes().end());
BOOST_ASSERT(!shortcut_durations.empty());
BOOST_ASSERT(!shortcut_distances.empty());
const NodeID to = *source;
if (shortcut_weight != INVALID_EDGE_WEIGHT && node != to)
{
const auto to_weight = weight + shortcut_weight;
const auto to_duration = duration + shortcut_durations.front();
const auto to_distance = distance + shortcut_distances.front();
if (!query_heap.WasInserted(to))
{
query_heap.Insert(to, to_weight, {node, true, to_duration});
query_heap.Insert(to, to_weight, {node, true, to_duration, to_distance});
}
else if (std::tie(to_weight, to_duration, node) <
else if (std::tie(to_weight, to_duration, to_distance, node) <
std::tie(query_heap.GetKey(to),
query_heap.GetData(to).duration,
query_heap.GetData(to).distance,
query_heap.GetData(to).parent))
{
query_heap.GetData(to) = {node, true, to_duration};
query_heap.GetData(to) = {node, true, to_duration, to_distance};
query_heap.DecreaseKey(to, to_weight);
}
}
++source;
shortcut_durations.advance_begin(1);
shortcut_distances.advance_begin(1);
}
BOOST_ASSERT(shortcut_durations.empty());
BOOST_ASSERT(shortcut_distances.empty());
}
}
@@ -143,25 +156,28 @@ void relaxOutgoingEdges(const DataFacade<mld::Algorithm> &facade,
const auto node_id = DIRECTION == FORWARD_DIRECTION ? node : facade.GetTarget(edge);
const auto node_weight = facade.GetNodeWeight(node_id);
const auto node_duration = facade.GetNodeDuration(node_id);
const auto node_distance = facade.GetNodeDistance(node_id);
const auto turn_weight = node_weight + facade.GetWeightPenaltyForEdgeID(turn_id);
const auto turn_duration = node_duration + facade.GetDurationPenaltyForEdgeID(turn_id);
BOOST_ASSERT_MSG(node_weight + turn_weight > 0, "edge weight is invalid");
const auto to_weight = weight + turn_weight;
const auto to_duration = duration + turn_duration;
const auto to_distance = distance + node_distance;
// New Node discovered -> Add to Heap + Node Info Storage
if (!query_heap.WasInserted(to))
{
query_heap.Insert(to, to_weight, {node, false, to_duration});
query_heap.Insert(to, to_weight, {node, false, to_duration, to_distance});
}
// Found a shorter Path -> Update weight and set new parent
else if (std::tie(to_weight, to_duration, node) <
else if (std::tie(to_weight, to_duration, to_distance, node) <
std::tie(query_heap.GetKey(to),
query_heap.GetData(to).duration,
query_heap.GetData(to).distance,
query_heap.GetData(to).parent))
{
query_heap.GetData(to) = {node, false, to_duration};
query_heap.GetData(to) = {node, false, to_duration, to_distance};
query_heap.DecreaseKey(to, to_weight);
}
}
@@ -182,11 +198,12 @@ oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
{
std::vector<EdgeWeight> weights(phantom_indices.size(), INVALID_EDGE_WEIGHT);
std::vector<EdgeDuration> durations(phantom_indices.size(), MAXIMAL_EDGE_DURATION);
std::vector<EdgeDistance> distances_table;
std::vector<EdgeDistance> distances_table(calculate_distance ? phantom_indices.size() : 0,
MAXIMAL_EDGE_DISTANCE);
std::vector<NodeID> middle_nodes_table(phantom_indices.size(), SPECIAL_NODEID);
// Collect destination (source) nodes into a map
std::unordered_multimap<NodeID, std::tuple<std::size_t, EdgeWeight, EdgeDuration>>
std::unordered_multimap<NodeID, std::tuple<std::size_t, EdgeWeight, EdgeDuration, EdgeDistance>>
target_nodes_index;
target_nodes_index.reserve(phantom_indices.size());
for (std::size_t index = 0; index < phantom_indices.size(); ++index)
@@ -201,13 +218,15 @@ oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
{phantom_node.forward_segment_id.id,
std::make_tuple(index,
phantom_node.GetForwardWeightPlusOffset(),
phantom_node.GetForwardDuration())});
phantom_node.GetForwardDuration(),
phantom_node.GetForwardDistance())});
if (phantom_node.IsValidReverseTarget())
target_nodes_index.insert(
{phantom_node.reverse_segment_id.id,
std::make_tuple(index,
phantom_node.GetReverseWeightPlusOffset(),
phantom_node.GetReverseDuration())});
phantom_node.GetReverseDuration(),
phantom_node.GetReverseDistance())});
}
else if (DIRECTION == REVERSE_DIRECTION)
{
@@ -216,13 +235,15 @@ oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
{phantom_node.forward_segment_id.id,
std::make_tuple(index,
-phantom_node.GetForwardWeightPlusOffset(),
-phantom_node.GetForwardDuration())});
-phantom_node.GetForwardDuration(),
-phantom_node.GetForwardDistance())});
if (phantom_node.IsValidReverseSource())
target_nodes_index.insert(
{phantom_node.reverse_segment_id.id,
std::make_tuple(index,
-phantom_node.GetReverseWeightPlusOffset(),
-phantom_node.GetReverseDuration())});
-phantom_node.GetReverseDuration(),
-phantom_node.GetReverseDistance())});
}
}
@@ -232,44 +253,55 @@ oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
auto &query_heap = *(engine_working_data.many_to_many_heap);
// Check if node is in the destinations list and update weights/durations
auto update_values = [&](NodeID node, EdgeWeight weight, EdgeDuration duration) {
auto candidates = target_nodes_index.equal_range(node);
for (auto it = candidates.first; it != candidates.second;)
{
std::size_t index;
EdgeWeight target_weight;
EdgeDuration target_duration;
std::tie(index, target_weight, target_duration) = it->second;
const auto path_weight = weight + target_weight;
if (path_weight >= 0)
auto update_values =
[&](NodeID node, EdgeWeight weight, EdgeDuration duration, EdgeDistance distance) {
auto candidates = target_nodes_index.equal_range(node);
for (auto it = candidates.first; it != candidates.second;)
{
const auto path_duration = duration + target_duration;
std::size_t index;
EdgeWeight target_weight;
EdgeDuration target_duration;
EdgeDistance target_distance;
std::tie(index, target_weight, target_duration, target_distance) = it->second;
if (std::tie(path_weight, path_duration) <
std::tie(weights[index], durations[index]))
const auto path_weight = weight + target_weight;
if (path_weight >= 0)
{
weights[index] = path_weight;
durations[index] = path_duration;
middle_nodes_table[index] = node;
const auto path_duration = duration + target_duration;
const auto path_distance = distance + target_distance;
EdgeDistance nulldistance = 0;
auto &current_distance =
distances_table.empty() ? nulldistance : distances_table[index];
if (std::tie(path_weight, path_duration, path_distance) <
std::tie(weights[index], durations[index], current_distance))
{
weights[index] = path_weight;
durations[index] = path_duration;
current_distance = path_distance;
middle_nodes_table[index] = node;
}
// Remove node from destinations list
it = target_nodes_index.erase(it);
}
else
{
++it;
}
// Remove node from destinations list
it = target_nodes_index.erase(it);
}
else
{
++it;
}
}
};
};
auto insert_node = [&](NodeID node, EdgeWeight initial_weight, EdgeDuration initial_duration) {
auto insert_node = [&](NodeID node,
EdgeWeight initial_weight,
EdgeDuration initial_duration,
EdgeDistance initial_distance) {
// Update single node paths
update_values(node, initial_weight, initial_duration);
update_values(node, initial_weight, initial_duration, initial_distance);
query_heap.Insert(node, initial_weight, {node, initial_duration});
query_heap.Insert(node, initial_weight, {node, initial_duration, initial_distance});
// Place adjacent nodes into heap
for (auto edge : facade.GetAdjacentEdgeRange(node))
@@ -292,8 +324,9 @@ oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
facade.GetWeightPenaltyForEdgeID(turn_id);
const auto edge_duration = initial_duration + facade.GetNodeDuration(node_id) +
facade.GetDurationPenaltyForEdgeID(turn_id);
const auto edge_distance = initial_distance + facade.GetNodeDistance(node_id);
query_heap.Insert(to, edge_weight, {node, edge_duration});
query_heap.Insert(to, edge_weight, {node, edge_duration, edge_distance});
}
}
};
@@ -307,14 +340,16 @@ oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
{
insert_node(phantom_node.forward_segment_id.id,
-phantom_node.GetForwardWeightPlusOffset(),
-phantom_node.GetForwardDuration());
-phantom_node.GetForwardDuration(),
-phantom_node.GetForwardDistance());
}
if (phantom_node.IsValidReverseSource())
{
insert_node(phantom_node.reverse_segment_id.id,
-phantom_node.GetReverseWeightPlusOffset(),
-phantom_node.GetReverseDuration());
-phantom_node.GetReverseDuration(),
-phantom_node.GetReverseDistance());
}
}
else if (DIRECTION == REVERSE_DIRECTION)
@@ -323,14 +358,16 @@ oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
{
insert_node(phantom_node.forward_segment_id.id,
phantom_node.GetForwardWeightPlusOffset(),
phantom_node.GetForwardDuration());
phantom_node.GetForwardDuration(),
phantom_node.GetForwardDistance());
}
if (phantom_node.IsValidReverseTarget())
{
insert_node(phantom_node.reverse_segment_id.id,
phantom_node.GetReverseWeightPlusOffset(),
phantom_node.GetReverseDuration());
phantom_node.GetReverseDuration(),
phantom_node.GetReverseDistance());
}
}
}
@@ -341,141 +378,23 @@ oneToManySearch(SearchEngineData<Algorithm> &engine_working_data,
const auto node = query_heap.DeleteMin();
const auto weight = query_heap.GetKey(node);
const auto duration = query_heap.GetData(node).duration;
const auto distance = query_heap.GetData(node).distance;
// Update values
update_values(node, weight, duration);
update_values(node, weight, duration, distance);
// Relax outgoing edges
relaxOutgoingEdges<DIRECTION>(facade,
node,
weight,
duration,
distance,
query_heap,
phantom_nodes,
phantom_index,
phantom_indices);
}
if (calculate_distance)
{
// Initialize unpacking heaps
engine_working_data.InitializeOrClearFirstThreadLocalStorage(
facade.GetNumberOfNodes(), facade.GetMaxBorderNodeID() + 1);
distances_table.resize(phantom_indices.size(), INVALID_EDGE_DISTANCE);
for (unsigned location = 0; location < phantom_indices.size(); ++location)
{
// Get the "middle" node that is the last node of a path
const NodeID middle_node_id = middle_nodes_table[location];
if (middle_node_id == SPECIAL_NODEID) // takes care of one-ways
{
continue;
}
// Retrieve the packed path from the heap
PackedPath packed_path = mld::retrievePackedPathFromSingleManyToManyHeap<DIRECTION>(
query_heap, middle_node_id);
// ... and reverse it to have packed edges in the correct order,
if (DIRECTION == FORWARD_DIRECTION)
{
std::reverse(packed_path.begin(), packed_path.end());
}
// ... unpack path
auto &forward_heap = *engine_working_data.forward_heap_1;
auto &reverse_heap = *engine_working_data.reverse_heap_1;
EdgeWeight weight = INVALID_EDGE_WEIGHT;
std::vector<NodeID> unpacked_nodes;
std::vector<EdgeID> unpacked_edges;
std::tie(weight, unpacked_nodes, unpacked_edges) =
unpackPathAndCalculateDistance(engine_working_data,
facade,
forward_heap,
reverse_heap,
DO_NOT_FORCE_LOOPS,
DO_NOT_FORCE_LOOPS,
INVALID_EDGE_WEIGHT,
packed_path,
middle_node_id,
phantom_nodes,
phantom_index,
phantom_indices);
// Accumulate the path length without the last node
auto annotation = 0.0;
BOOST_ASSERT(!unpacked_nodes.empty());
for (auto node = unpacked_nodes.begin(), last_node = std::prev(unpacked_nodes.end());
node != last_node;
++node)
{
annotation += computeEdgeDistance(facade, *node);
}
// ... and add negative source and positive target offsets
// ⚠ for REVERSE_DIRECTION original source and target phantom nodes are swapped
// Get source and target phantom nodes
// * 1-to-N: source is a single index, target is the corresponding from the indices list
// * N-to-1: source is the corresponding from the indices list, target is a single index
auto source_phantom_index = phantom_index;
auto target_phantom_index = phantom_indices[location];
if (DIRECTION == REVERSE_DIRECTION)
{
std::swap(source_phantom_index, target_phantom_index);
}
const auto &source_phantom = phantom_nodes[source_phantom_index];
const auto &target_phantom = phantom_nodes[target_phantom_index];
const NodeID source_node = unpacked_nodes.front();
const NodeID target_node = unpacked_nodes.back();
EdgeDistance source_offset = 0., target_offset = 0.;
if (source_phantom.IsValidForwardSource() &&
source_phantom.forward_segment_id.id == source_node)
{
// ............ <-- calculateEGBAnnotation returns distance from 0
// to 3
// -->s <-- subtract offset to start at source
// ......... <-- want this distance as result
// entry 0---1---2---3--- <-- 3 is exit node
source_offset = source_phantom.GetForwardDistance();
}
else if (source_phantom.IsValidReverseSource() &&
source_phantom.reverse_segment_id.id == source_node)
{
// ............ <-- calculateEGBAnnotation returns distance from 0 to 3
// s<------- <-- subtract offset to start at source
// ... <-- want this distance
// entry 0---1---2---3 <-- 3 is exit node
source_offset = source_phantom.GetReverseDistance();
}
if (target_phantom.IsValidForwardTarget() &&
target_phantom.forward_segment_id.id == target_node)
{
// ............ <-- calculateEGBAnnotation returns distance from 0
// to 3
// ++>t <-- add offset to get to target
// ................ <-- want this distance as result
// entry 0---1---2---3--- <-- 3 is exit node
target_offset = target_phantom.GetForwardDistance();
}
else if (target_phantom.IsValidReverseTarget() &&
target_phantom.reverse_segment_id.id == target_node)
{
// ............ <-- calculateEGBAnnotation returns distance from 0
// to 3
// <++t <-- add offset to get from target
// ................ <-- want this distance as result
// entry 0---1---2---3--- <-- 3 is exit node
target_offset = target_phantom.GetReverseDistance();
}
distances_table[location] = -source_offset + annotation + target_offset;
}
}
return std::make_pair(durations, distances_table);
}
@@ -491,12 +410,14 @@ void forwardRoutingStep(const DataFacade<Algorithm> &facade,
const std::vector<NodeBucket> &search_space_with_buckets,
std::vector<EdgeWeight> &weights_table,
std::vector<EdgeDuration> &durations_table,
std::vector<EdgeDistance> &distances_table,
std::vector<NodeID> &middle_nodes_table,
const PhantomNode &phantom_node)
{
const auto node = query_heap.DeleteMin();
const auto source_weight = query_heap.GetKey(node);
const auto source_duration = query_heap.GetData(node).duration;
const auto source_distance = query_heap.GetData(node).distance;
// Check if each encountered node has an entry
const auto &bucket_list = std::equal_range(search_space_with_buckets.begin(),
@@ -509,6 +430,7 @@ void forwardRoutingStep(const DataFacade<Algorithm> &facade,
const auto column_idx = current_bucket.column_index;
const auto target_weight = current_bucket.weight;
const auto target_duration = current_bucket.duration;
const auto target_distance = current_bucket.distance;
// Get the value location in the results tables:
// * row-major direct (row_idx, column_idx) index for forward direction
@@ -519,21 +441,27 @@ void forwardRoutingStep(const DataFacade<Algorithm> &facade,
auto &current_weight = weights_table[location];
auto &current_duration = durations_table[location];
EdgeDistance nulldistance = 0;
auto &current_distance = distances_table.empty() ? nulldistance : distances_table[location];
// Check if new weight is better
auto new_weight = source_weight + target_weight;
auto new_duration = source_duration + target_duration;
auto new_distance = source_distance + target_distance;
if (new_weight >= 0 &&
std::tie(new_weight, new_duration) < std::tie(current_weight, current_duration))
std::tie(new_weight, new_duration, new_distance) <
std::tie(current_weight, current_duration, current_distance))
{
current_weight = new_weight;
current_duration = new_duration;
current_distance = new_distance;
middle_nodes_table[location] = node;
}
}
relaxOutgoingEdges<DIRECTION>(
facade, node, source_weight, source_duration, query_heap, phantom_node);
facade, node, source_weight, source_duration, source_distance, query_heap, phantom_node);
}
template <bool DIRECTION>
@@ -546,18 +474,25 @@ void backwardRoutingStep(const DataFacade<Algorithm> &facade,
const auto node = query_heap.DeleteMin();
const auto target_weight = query_heap.GetKey(node);
const auto target_duration = query_heap.GetData(node).duration;
const auto target_distance = query_heap.GetData(node).distance;
const auto parent = query_heap.GetData(node).parent;
const auto from_clique_arc = query_heap.GetData(node).from_clique_arc;
// Store settled nodes in search space bucket
search_space_with_buckets.emplace_back(
node, parent, from_clique_arc, column_idx, target_weight, target_duration);
node, parent, from_clique_arc, column_idx, target_weight, target_duration, target_distance);
const auto &partition = facade.GetMultiLevelPartition();
const auto maximal_level = partition.GetNumberOfLevels() - 1;
relaxOutgoingEdges<!DIRECTION>(
facade, node, target_weight, target_duration, query_heap, phantom_node, maximal_level);
relaxOutgoingEdges<!DIRECTION>(facade,
node,
target_weight,
target_duration,
target_distance,
query_heap,
phantom_node,
maximal_level);
}
template <bool DIRECTION>
@@ -596,182 +531,6 @@ void retrievePackedPathFromSearchSpace(NodeID middle_node_id,
}
}
template <bool DIRECTION>
void calculateDistances(typename SearchEngineData<mld::Algorithm>::ManyToManyQueryHeap &query_heap,
const DataFacade<mld::Algorithm> &facade,
const std::vector<PhantomNode> &phantom_nodes,
const std::vector<std::size_t> &target_indices,
const unsigned row_idx,
const std::size_t source_index,
const unsigned number_of_sources,
const unsigned number_of_targets,
const std::vector<NodeBucket> &search_space_with_buckets,
std::vector<EdgeDistance> &distances_table,
const std::vector<NodeID> &middle_nodes_table,
SearchEngineData<mld::Algorithm> &engine_working_data)
{
engine_working_data.InitializeOrClearFirstThreadLocalStorage(facade.GetNumberOfNodes(),
facade.GetMaxBorderNodeID() + 1);
for (unsigned column_idx = 0; column_idx < number_of_targets; ++column_idx)
{
// Step 1: Get source and target phantom nodes that were used in the bucketed search
auto source_phantom_index = source_index;
auto target_phantom_index = target_indices[column_idx];
const auto &source_phantom = phantom_nodes[source_phantom_index];
const auto &target_phantom = phantom_nodes[target_phantom_index];
const auto location = DIRECTION == FORWARD_DIRECTION
? row_idx * number_of_targets + column_idx
: row_idx + column_idx * number_of_sources;
if (source_phantom_index == target_phantom_index)
{
distances_table[location] = 0.0;
continue;
}
NodeID middle_node_id = middle_nodes_table[location];
if (middle_node_id == SPECIAL_NODEID) // takes care of one-ways
{
distances_table[location] = INVALID_EDGE_DISTANCE;
continue;
}
// Step 2: Find path from source to middle node
PackedPath packed_path =
mld::retrievePackedPathFromSingleManyToManyHeap<DIRECTION>(query_heap, middle_node_id);
if (DIRECTION == FORWARD_DIRECTION)
{
std::reverse(packed_path.begin(), packed_path.end());
}
auto &forward_heap = *engine_working_data.forward_heap_1;
auto &reverse_heap = *engine_working_data.reverse_heap_1;
EdgeWeight weight = INVALID_EDGE_WEIGHT;
std::vector<NodeID> unpacked_nodes_from_source;
std::vector<EdgeID> unpacked_edges;
std::tie(weight, unpacked_nodes_from_source, unpacked_edges) =
unpackPathAndCalculateDistance(engine_working_data,
facade,
forward_heap,
reverse_heap,
DO_NOT_FORCE_LOOPS,
DO_NOT_FORCE_LOOPS,
INVALID_EDGE_WEIGHT,
packed_path,
middle_node_id,
source_phantom);
// Step 3: Find path from middle to target node
packed_path.clear();
retrievePackedPathFromSearchSpace<DIRECTION>(
middle_node_id, column_idx, search_space_with_buckets, packed_path);
if (DIRECTION == REVERSE_DIRECTION)
{
std::reverse(packed_path.begin(), packed_path.end());
}
std::vector<NodeID> unpacked_nodes_to_target;
std::tie(weight, unpacked_nodes_to_target, unpacked_edges) =
unpackPathAndCalculateDistance(engine_working_data,
facade,
forward_heap,
reverse_heap,
DO_NOT_FORCE_LOOPS,
DO_NOT_FORCE_LOOPS,
INVALID_EDGE_WEIGHT,
packed_path,
middle_node_id,
target_phantom);
if (DIRECTION == REVERSE_DIRECTION)
{
std::swap(unpacked_nodes_to_target, unpacked_nodes_from_source);
}
// Step 4: Compute annotation value along the path nodes without the target node
auto annotation = 0.0;
for (auto node = unpacked_nodes_from_source.begin(),
last_node = std::prev(unpacked_nodes_from_source.end());
node != last_node;
++node)
{
annotation += computeEdgeDistance(facade, *node);
}
for (auto node = unpacked_nodes_to_target.begin(),
last_node = std::prev(unpacked_nodes_to_target.end());
node != last_node;
++node)
{
annotation += computeEdgeDistance(facade, *node);
}
// Step 5: Get phantom node offsets and compute the annotation value
EdgeDistance source_offset = 0., target_offset = 0.;
{
// ⚠ for REVERSE_DIRECTION original source and target phantom nodes are swapped
if (DIRECTION == REVERSE_DIRECTION)
{
std::swap(source_phantom_index, target_phantom_index);
}
const auto &source_phantom = phantom_nodes[source_phantom_index];
const auto &target_phantom = phantom_nodes[target_phantom_index];
NodeID source_node = unpacked_nodes_from_source.front();
NodeID target_node = unpacked_nodes_to_target.back();
if (source_phantom.IsValidForwardSource() &&
source_phantom.forward_segment_id.id == source_node)
{
// ............ <-- calculateEGBAnnotation returns distance from 0
// to 3
// -->s <-- subtract offset to start at source
// ......... <-- want this distance as result
// entry 0---1---2---3--- <-- 3 is exit node
source_offset = source_phantom.GetForwardDistance();
}
else if (source_phantom.IsValidReverseSource() &&
source_phantom.reverse_segment_id.id == source_node)
{
// ............ <-- calculateEGBAnnotation returns distance from 0 to 3
// s<------- <-- subtract offset to start at source
// ... <-- want this distance
// entry 0---1---2---3 <-- 3 is exit node
source_offset = source_phantom.GetReverseDistance();
}
if (target_phantom.IsValidForwardTarget() &&
target_phantom.forward_segment_id.id == target_node)
{
// ............ <-- calculateEGBAnnotation returns distance from 0
// to 3
// ++>t <-- add offset to get to target
// ................ <-- want this distance as result
// entry 0---1---2---3--- <-- 3 is exit node
target_offset = target_phantom.GetForwardDistance();
}
else if (target_phantom.IsValidReverseTarget() &&
target_phantom.reverse_segment_id.id == target_node)
{
// ............ <-- calculateEGBAnnotation returns distance from 0
// to 3
// <++t <-- add offset to get from target
// ................ <-- want this distance as result
// entry 0---1---2---3--- <-- 3 is exit node
target_offset = target_phantom.GetReverseDistance();
}
}
distances_table[location] = -source_offset + annotation + target_offset;
}
}
template <bool DIRECTION>
std::pair<std::vector<EdgeDuration>, std::vector<EdgeDistance>>
manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
@@ -787,7 +546,8 @@ manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
std::vector<EdgeWeight> weights_table(number_of_entries, INVALID_EDGE_WEIGHT);
std::vector<EdgeDuration> durations_table(number_of_entries, MAXIMAL_EDGE_DURATION);
std::vector<EdgeDistance> distances_table;
std::vector<EdgeDistance> distances_table(calculate_distance ? number_of_entries : 0,
INVALID_EDGE_DISTANCE);
std::vector<NodeID> middle_nodes_table(number_of_entries, SPECIAL_NODEID);
std::vector<NodeBucket> search_space_with_buckets;
@@ -846,25 +606,9 @@ manyToManySearch(SearchEngineData<Algorithm> &engine_working_data,
search_space_with_buckets,
weights_table,
durations_table,
middle_nodes_table,
source_phantom);
}
if (calculate_distance)
{
distances_table.resize(number_of_entries, INVALID_EDGE_DISTANCE);
calculateDistances<DIRECTION>(query_heap,
facade,
phantom_nodes,
target_indices, // source_indices
row_idx,
source_index,
number_of_sources,
number_of_targets,
search_space_with_buckets,
distances_table,
middle_nodes_table,
engine_working_data);
source_phantom);
}
}
@@ -892,12 +636,8 @@ manyToManySearch(SearchEngineData<mld::Algorithm> &engine_working_data,
const std::vector<PhantomNode> &phantom_nodes,
const std::vector<std::size_t> &source_indices,
const std::vector<std::size_t> &target_indices,
const bool calculate_distance,
const bool calculate_duration)
const bool calculate_distance)
{
(void)calculate_duration; // flag stub to use for calculating distances in matrix in mld in the
// future
if (source_indices.size() == 1)
{ // TODO: check if target_indices.size() == 1 and do a bi-directional search
return mld::oneToManySearch<FORWARD_DIRECTION>(engine_working_data,
+8 -16
View File
@@ -227,9 +227,6 @@ SubMatchingList mapMatching(SearchEngineData<Algorithm> &engine_working_data,
{
continue;
}
forward_heap.Clear();
const auto &source_phantom = prev_unbroken_timestamps_list[s].phantom_node;
insertSourceInHeap(forward_heap, source_phantom);
for (const auto s_prime : util::irange<std::size_t>(0UL, current_viterbi.size()))
{
@@ -240,19 +237,14 @@ SubMatchingList mapMatching(SearchEngineData<Algorithm> &engine_working_data,
continue;
}
reverse_heap.Clear();
const auto &target_phantom = current_timestamps_list[s_prime].phantom_node;
insertTargetInHeap(reverse_heap, target_phantom);
double network_distance = getNetworkDistance(engine_working_data,
facade,
forward_heap,
reverse_heap,
source_phantom,
target_phantom,
weight_upper_bound);
network_distance = std::round(network_distance * 10) / 10;
double network_distance =
getNetworkDistance(engine_working_data,
facade,
forward_heap,
reverse_heap,
prev_unbroken_timestamps_list[s].phantom_node,
current_timestamps_list[s_prime].phantom_node,
weight_upper_bound);
// get distance diff between loc1/2 and locs/s_prime
const auto d_t = std::abs(network_distance - haversine_distance);
@@ -33,79 +33,6 @@ bool needsLoopBackwards(const PhantomNodes &phantoms)
return needsLoopBackwards(phantoms.source_phantom, phantoms.target_phantom);
}
EdgeDistance adjustPathDistanceToPhantomNodes(const std::vector<NodeID> &path,
const PhantomNode &source_phantom,
const PhantomNode &target_phantom,
const EdgeDistance uncorrected_distance)
{
EdgeDistance distance = uncorrected_distance;
if (!path.empty())
{
// check the direction of travel to figure out how to calculate the offset to/from
// the source/target
if (source_phantom.forward_segment_id.id == path.front())
{
// ............ <-- calculateEGBAnnotation returns distance from 0 to 3
// -->s <-- subtract offset to start at source
// ......... <-- want this distance as result
// entry 0---1---2---3--- <-- 3 is exit node
distance -= source_phantom.GetForwardDistance();
}
else if (source_phantom.reverse_segment_id.id == path.front())
{
// ............ <-- calculateEGBAnnotation returns distance from 0 to 3
// s<------- <-- subtract offset to start at source
// ... <-- want this distance
// entry 0---1---2---3 <-- 3 is exit node
distance -= source_phantom.GetReverseDistance();
}
if (target_phantom.forward_segment_id.id == path.back())
{
// ............ <-- calculateEGBAnnotation returns distance from 0 to 3
// ++>t <-- add offset to get to target
// ................ <-- want this distance as result
// entry 0---1---2---3--- <-- 3 is exit node
distance += target_phantom.GetForwardDistance();
}
else if (target_phantom.reverse_segment_id.id == path.back())
{
// ............ <-- calculateEGBAnnotation returns distance from 0 to 3
// <++t <-- add offset to get from target
// ................ <-- want this distance as result
// entry 0---1---2---3--- <-- 3 is exit node
distance += target_phantom.GetReverseDistance();
}
}
else
{
// there is no shortcut to unpack. source and target are on the same EBG Node.
// if the offset of the target is greater than the offset of the source, subtract it
if (target_phantom.GetForwardDistance() > source_phantom.GetForwardDistance())
{
// --------->t <-- offsets
// ->s <-- subtract source offset from target offset
// ......... <-- want this distance as result
// entry 0---1---2---3--- <-- 3 is exit node
distance = target_phantom.GetForwardDistance() - source_phantom.GetForwardDistance();
}
else
{
// s<--- <-- offsets
// t<--------- <-- subtract source offset from target offset
// ...... <-- want this distance as result
// entry 0---1---2---3--- <-- 3 is exit node
distance = target_phantom.GetReverseDistance() - source_phantom.GetReverseDistance();
}
}
BOOST_ASSERT_MSG(distance >= 0 || distance > -1.0f,
"Distance correction generated negative number");
// guard against underflow errors caused by rounding
distance = std::max(EdgeDistance{0}, distance);
return distance;
}
} // namespace routing_algorithms
} // namespace engine
} // namespace osrm
@@ -100,7 +100,7 @@ void search(SearchEngineData<Algorithm> & /*engine_working_data*/,
const PhantomNodes & /*phantom_nodes*/,
const EdgeWeight weight_upper_bound)
{
if (forward_heap.Empty() && reverse_heap.Empty())
if (forward_heap.Empty() || reverse_heap.Empty())
{
weight = INVALID_EDGE_WEIGHT;
return;
@@ -110,14 +110,10 @@ void search(SearchEngineData<Algorithm> & /*engine_working_data*/,
weight = weight_upper_bound;
// get offset to account for offsets on phantom nodes on compressed edges
EdgeWeight min_edge_offset = 0;
if (forward_heap.Size() > 0)
{
min_edge_offset = std::min(min_edge_offset, forward_heap.MinKey());
BOOST_ASSERT(min_edge_offset <= 0);
}
const auto min_edge_offset = std::min(0, forward_heap.MinKey());
BOOST_ASSERT(min_edge_offset <= 0);
// we only every insert negative offsets for nodes in the forward heap
BOOST_ASSERT(reverse_heap.Empty() || reverse_heap.MinKey() >= 0);
BOOST_ASSERT(reverse_heap.MinKey() >= 0);
// run two-Target Dijkstra routing step.
while (0 < (forward_heap.Size() + reverse_heap.Size()))
@@ -180,6 +176,11 @@ double getNetworkDistance(SearchEngineData<Algorithm> &engine_working_data,
const PhantomNode &target_phantom,
EdgeWeight weight_upper_bound)
{
forward_heap.Clear();
reverse_heap.Clear();
insertNodesInHeaps(forward_heap, reverse_heap, {source_phantom, target_phantom});
EdgeWeight weight = INVALID_EDGE_WEIGHT;
std::vector<NodeID> packed_path;
search(engine_working_data,
@@ -198,31 +199,14 @@ double getNetworkDistance(SearchEngineData<Algorithm> &engine_working_data,
return std::numeric_limits<double>::max();
}
EdgeDistance distance = 0;
std::vector<PathData> unpacked_path;
unpackPath(facade,
packed_path.begin(),
packed_path.end(),
{source_phantom, target_phantom},
unpacked_path);
std::vector<NodeID> unpacked_nodes;
unpacked_nodes.reserve(packed_path.size());
if (!packed_path.empty())
{
unpacked_nodes.push_back(packed_path.front());
unpackPath(
facade, packed_path.begin(), packed_path.end(), [&](const auto &edge, const auto &) {
BOOST_ASSERT(edge.first == unpacked_nodes.back());
unpacked_nodes.push_back(edge.second);
});
distance = std::accumulate(unpacked_nodes.begin(),
std::prev(unpacked_nodes.end()),
EdgeDistance{0},
[&](const EdgeDistance distance, const auto node_id) {
return distance + computeEdgeDistance(facade, node_id);
});
}
distance =
adjustPathDistanceToPhantomNodes(unpacked_nodes, source_phantom, target_phantom, distance);
return distance;
return getPathDistance(facade, unpacked_path, source_phantom, target_phantom);
}
} // namespace ch
+27 -11
View File
@@ -114,6 +114,13 @@ void EdgeBasedGraphFactory::GetEdgeBasedNodeDurations(
swap(m_edge_based_node_durations, output_node_durations);
}
void EdgeBasedGraphFactory::GetEdgeBasedNodeDistances(
std::vector<EdgeDistance> &output_node_distances)
{
using std::swap; // Koenig swap
swap(m_edge_based_node_distances, output_node_distances);
}
std::uint32_t EdgeBasedGraphFactory::GetConnectivityChecksum() const
{
return m_connectivity_checksum;
@@ -291,8 +298,12 @@ unsigned EdgeBasedGraphFactory::LabelEdgeBasedNodes()
{
// heuristic: node-based graph node is a simple intersection with four edges
// (edge-based nodes)
m_edge_based_node_weights.reserve(4 * m_node_based_graph.GetNumberOfNodes());
m_edge_based_node_durations.reserve(4 * m_node_based_graph.GetNumberOfNodes());
constexpr std::size_t ESTIMATED_EDGE_COUNT = 4;
m_edge_based_node_weights.reserve(ESTIMATED_EDGE_COUNT * m_node_based_graph.GetNumberOfNodes());
m_edge_based_node_durations.reserve(ESTIMATED_EDGE_COUNT *
m_node_based_graph.GetNumberOfNodes());
m_edge_based_node_distances.reserve(ESTIMATED_EDGE_COUNT *
m_node_based_graph.GetNumberOfNodes());
nbe_to_ebn_mapping.resize(m_node_based_graph.GetEdgeCapacity(), SPECIAL_NODEID);
// renumber edge based node of outgoing edges
@@ -310,6 +321,7 @@ unsigned EdgeBasedGraphFactory::LabelEdgeBasedNodes()
m_edge_based_node_weights.push_back(edge_data.weight);
m_edge_based_node_durations.push_back(edge_data.duration);
m_edge_based_node_distances.push_back(edge_data.distance);
BOOST_ASSERT(numbered_edges_count < m_node_based_graph.GetNumberOfEdges());
nbe_to_ebn_mapping[current_edge] = numbered_edges_count;
@@ -407,6 +419,8 @@ EdgeBasedGraphFactory::GenerateEdgeExpandedNodes(const WayRestrictionMap &way_re
m_edge_based_node_weights.push_back(ebn_weight);
m_edge_based_node_durations.push_back(
m_edge_based_node_durations[nbe_to_ebn_mapping[eid]]);
m_edge_based_node_distances.push_back(
m_edge_based_node_distances[nbe_to_ebn_mapping[eid]]);
edge_based_node_id++;
progress.PrintStatus(progress_counter++);
@@ -416,6 +430,7 @@ EdgeBasedGraphFactory::GenerateEdgeExpandedNodes(const WayRestrictionMap &way_re
BOOST_ASSERT(m_edge_based_node_segments.size() == m_edge_based_node_is_startpoint.size());
BOOST_ASSERT(m_number_of_edge_based_nodes == m_edge_based_node_weights.size());
BOOST_ASSERT(m_number_of_edge_based_nodes == m_edge_based_node_durations.size());
BOOST_ASSERT(m_number_of_edge_based_nodes == m_edge_based_node_distances.size());
util::Log() << "Generated " << m_number_of_edge_based_nodes << " nodes ("
<< way_restriction_map.NumberOfDuplicatedNodes()
@@ -652,16 +667,17 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
// auto turn_id = m_edge_based_edge_list.size();
auto weight = boost::numeric_cast<EdgeWeight>(edge_data1.weight + weight_penalty);
auto duration = boost::numeric_cast<EdgeWeight>(edge_data1.duration + duration_penalty);
auto distance = boost::numeric_cast<EdgeDistance>(edge_data1.distance);
EdgeBasedEdge edge_based_edge = {
edge_based_node_from,
edge_based_node_to,
SPECIAL_NODEID, // This will be updated once the main loop
// completes!
weight,
duration,
true,
false};
EdgeBasedEdge edge_based_edge = {edge_based_node_from,
edge_based_node_to,
SPECIAL_NODEID, // This will be updated once the main
// loop completes!
weight,
duration,
distance,
true,
false};
// We write out the mapping between the edge-expanded edges and the original nodes.
// Since each edge represents a possible maneuver, external programs can use this to
+4
View File
@@ -387,12 +387,16 @@ void ExtractionContainers::PrepareEdges(ScriptingEnvironment &scripting_environm
const auto weight = edge_iterator->weight_data(distance);
const auto duration = edge_iterator->duration_data(distance);
const auto accurate_distance =
util::coordinate_calculation::fccApproximateDistance(source_coord, target_coord);
ExtractionSegment segment(source_coord, target_coord, distance, weight, duration);
scripting_environment.ProcessSegment(segment);
auto &edge = edge_iterator->result;
edge.weight = std::max<EdgeWeight>(1, std::round(segment.weight * weight_multiplier));
edge.duration = std::max<EdgeWeight>(1, std::round(segment.duration * 10.));
edge.distance = accurate_distance;
// assign new node id
const auto node_id = mapExternalToInternalNodeID(
+8 -2
View File
@@ -242,6 +242,7 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
std::vector<bool> node_is_startpoint;
std::vector<EdgeWeight> edge_based_node_weights;
std::vector<EdgeDuration> edge_based_node_durations;
std::vector<EdgeDistance> edge_based_node_distances;
std::uint32_t ebg_connectivity_checksum = 0;
// Create a node-based graph from the OSRM file
@@ -322,6 +323,7 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
node_is_startpoint,
edge_based_node_weights,
edge_based_node_durations,
edge_based_node_distances,
edge_based_edge_list,
ebg_connectivity_checksum);
@@ -345,8 +347,10 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
util::Log() << "Saving edge-based node weights to file.";
TIMER_START(timer_write_node_weights);
extractor::files::writeEdgeBasedNodeWeightsDurations(
config.GetPath(".osrm.enw"), edge_based_node_weights, edge_based_node_durations);
extractor::files::writeEdgeBasedNodeWeightsDurationsDistances(config.GetPath(".osrm.enw"),
edge_based_node_weights,
edge_based_node_durations,
edge_based_node_distances);
TIMER_STOP(timer_write_node_weights);
util::Log() << "Done writing. (" << TIMER_SEC(timer_write_node_weights) << ")";
@@ -736,6 +740,7 @@ EdgeID Extractor::BuildEdgeExpandedGraph(
std::vector<bool> &node_is_startpoint,
std::vector<EdgeWeight> &edge_based_node_weights,
std::vector<EdgeDuration> &edge_based_node_durations,
std::vector<EdgeDistance> &edge_based_node_distances,
util::DeallocatingVector<EdgeBasedEdge> &edge_based_edge_list,
std::uint32_t &connectivity_checksum)
{
@@ -786,6 +791,7 @@ EdgeID Extractor::BuildEdgeExpandedGraph(
edge_based_graph_factory.GetStartPointMarkers(node_is_startpoint);
edge_based_graph_factory.GetEdgeBasedNodeWeights(edge_based_node_weights);
edge_based_graph_factory.GetEdgeBasedNodeDurations(edge_based_node_durations);
edge_based_graph_factory.GetEdgeBasedNodeDistances(edge_based_node_distances);
connectivity_checksum = edge_based_graph_factory.GetConnectivityChecksum();
return number_of_edge_based_nodes;
+2
View File
@@ -415,6 +415,7 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
OSMNodeID{static_cast<std::uint64_t>(last_node.ref())},
0, // weight
0, // duration
0, // distance
{}, // geometry id
static_cast<AnnotationID>(annotation_data_id),
{true,
@@ -450,6 +451,7 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
OSMNodeID{static_cast<std::uint64_t>(last_node.ref())},
0, // weight
0, // duration
0, // distance
{}, // geometry id
static_cast<AnnotationID>(annotation_data_id),
{false,
+17
View File
@@ -259,6 +259,7 @@ void GraphCompressor::Compress(
const auto forward_weight2 = fwd_edge_data2.weight;
const auto forward_duration1 = fwd_edge_data1.duration;
const auto forward_duration2 = fwd_edge_data2.duration;
const auto forward_distance2 = fwd_edge_data2.distance;
BOOST_ASSERT(0 != forward_weight1);
BOOST_ASSERT(0 != forward_weight2);
@@ -267,6 +268,17 @@ void GraphCompressor::Compress(
const auto reverse_weight2 = rev_edge_data2.weight;
const auto reverse_duration1 = rev_edge_data1.duration;
const auto reverse_duration2 = rev_edge_data2.duration;
const auto reverse_distance2 = rev_edge_data2.distance;
#ifndef NDEBUG
// Because distances are symmetrical, we only need one
// per edge - here we double-check that they match
// their mirrors.
const auto reverse_distance1 = rev_edge_data1.distance;
const auto forward_distance1 = fwd_edge_data1.distance;
BOOST_ASSERT(forward_distance1 == reverse_distance2);
BOOST_ASSERT(forward_distance2 == reverse_distance1);
#endif
BOOST_ASSERT(0 != reverse_weight1);
BOOST_ASSERT(0 != reverse_weight2);
@@ -279,6 +291,10 @@ void GraphCompressor::Compress(
graph.GetEdgeData(forward_e1).duration += forward_duration2;
graph.GetEdgeData(reverse_e1).duration += reverse_duration2;
// add distance of e2's to e1
graph.GetEdgeData(forward_e1).distance += forward_distance2;
graph.GetEdgeData(reverse_e1).distance += reverse_distance2;
if (node_weight_penalty != INVALID_EDGE_WEIGHT &&
node_duration_penalty != MAXIMAL_EDGE_DURATION)
{
@@ -286,6 +302,7 @@ void GraphCompressor::Compress(
graph.GetEdgeData(reverse_e1).weight += node_weight_penalty;
graph.GetEdgeData(forward_e1).duration += node_duration_penalty;
graph.GetEdgeData(reverse_e1).duration += node_duration_penalty;
// Note: no penalties for distances
}
// extend e1's to targets of e2's
+93 -12
View File
@@ -9,12 +9,15 @@
#include "osrm/trip_parameters.hpp"
#include <exception>
#include <sstream>
#include <type_traits>
#include <utility>
#include "nodejs/node_osrm.hpp"
#include "nodejs/node_osrm_support.hpp"
#include "util/json_renderer.hpp"
namespace node_osrm
{
@@ -122,6 +125,8 @@ inline void async(const Nan::FunctionCallbackInfo<v8::Value> &info,
if (!params)
return;
auto pluginParams = argumentsToPluginParameters(info);
BOOST_ASSERT(params->IsValid());
if (!info[info.Length() - 1]->IsFunction())
@@ -137,9 +142,89 @@ inline void async(const Nan::FunctionCallbackInfo<v8::Value> &info,
Worker(std::shared_ptr<osrm::OSRM> osrm_,
ParamPtr params_,
ServiceMemFn service,
Nan::Callback *callback)
Nan::Callback *callback,
PluginParameters pluginParams_)
: Base(callback), osrm{std::move(osrm_)}, service{std::move(service)},
params{std::move(params_)}
params{std::move(params_)}, pluginParams{std::move(pluginParams_)}
{
}
void Execute() override try
{
osrm::json::Object r;
const auto status = ((*osrm).*(service))(*params, r);
ParseResult(status, r);
if (pluginParams.renderJSONToBuffer)
{
std::ostringstream buf;
osrm::util::json::render(buf, r);
result = buf.str();
}
else
{
result = r;
}
}
catch (const std::exception &e)
{
SetErrorMessage(e.what());
}
void HandleOKCallback() override
{
Nan::HandleScope scope;
const constexpr auto argc = 2u;
v8::Local<v8::Value> argv[argc] = {Nan::Null(), render(result)};
callback->Call(argc, argv);
}
// Keeps the OSRM object alive even after shutdown until we're done with callback
std::shared_ptr<osrm::OSRM> osrm;
ServiceMemFn service;
const ParamPtr params;
const PluginParameters pluginParams;
ObjectOrString result;
};
auto *callback = new Nan::Callback{info[info.Length() - 1].As<v8::Function>()};
Nan::AsyncQueueWorker(
new Worker{self->this_, std::move(params), service, callback, std::move(pluginParams)});
}
template <typename ParameterParser, typename ServiceMemFn>
inline void asyncForTiles(const Nan::FunctionCallbackInfo<v8::Value> &info,
ParameterParser argsToParams,
ServiceMemFn service,
bool requires_multiple_coordinates)
{
auto params = argsToParams(info, requires_multiple_coordinates);
if (!params)
return;
auto pluginParams = argumentsToPluginParameters(info);
BOOST_ASSERT(params->IsValid());
if (!info[info.Length() - 1]->IsFunction())
return Nan::ThrowTypeError("last argument must be a callback function");
auto *const self = Nan::ObjectWrap::Unwrap<Engine>(info.Holder());
using ParamPtr = decltype(params);
struct Worker final : Nan::AsyncWorker
{
using Base = Nan::AsyncWorker;
Worker(std::shared_ptr<osrm::OSRM> osrm_,
ParamPtr params_,
ServiceMemFn service,
Nan::Callback *callback,
PluginParameters pluginParams_)
: Base(callback), osrm{std::move(osrm_)}, service{std::move(service)},
params{std::move(params_)}, pluginParams{std::move(pluginParams_)}
{
}
@@ -167,18 +252,14 @@ inline void async(const Nan::FunctionCallbackInfo<v8::Value> &info,
std::shared_ptr<osrm::OSRM> osrm;
ServiceMemFn service;
const ParamPtr params;
const PluginParameters pluginParams;
// All services return json::Object .. except for Tile!
using ObjectOrString =
typename std::conditional<std::is_same<ParamPtr, tile_parameters_ptr>::value,
std::string,
osrm::json::Object>::type;
ObjectOrString result;
std::string result;
};
auto *callback = new Nan::Callback{info[info.Length() - 1].As<v8::Function>()};
Nan::AsyncQueueWorker(new Worker{self->this_, std::move(params), service, callback});
Nan::AsyncQueueWorker(
new Worker{self->this_, std::move(params), service, callback, std::move(pluginParams)});
}
// clang-format off
@@ -282,7 +363,7 @@ NAN_METHOD(Engine::nearest) //
* @param {Function} callback
*
* @returns {Object} containing `durations`, `sources`, and `destinations`.
* @returns {Object} containing `durations`, `distances`, `sources`, and `destinations`.
* **`durations`**: array of arrays that stores the matrix in row-major order. `durations[i][j]` gives the travel time from the i-th waypoint to the j-th waypoint.
* Values are given in seconds.
* **`distances`**: array of arrays that stores the matrix in row-major order. `distances[i][j]` gives the travel time from the i-th waypoint to the j-th waypoint.
@@ -341,7 +422,7 @@ NAN_METHOD(Engine::table) //
// clang-format on
NAN_METHOD(Engine::tile)
{
async(info, &argumentsToTileParameters, &osrm::OSRM::Tile, {/*unused*/});
asyncForTiles(info, &argumentsToTileParameters, &osrm::OSRM::Tile, {/*unused*/});
}
// clang-format off
+5 -2
View File
@@ -147,12 +147,15 @@ int Partitioner::Run(const PartitionerConfig &config)
{
std::vector<EdgeWeight> node_weights;
std::vector<EdgeDuration> node_durations;
std::vector<EdgeDuration> node_distances;
extractor::files::readEdgeBasedNodeWeightsDurations(
config.GetPath(".osrm.enw"), node_weights, node_durations);
extractor::files::readEdgeBasedNodeDistances(config.GetPath(".osrm.enw"), node_distances);
util::inplacePermutation(node_weights.begin(), node_weights.end(), permutation);
util::inplacePermutation(node_durations.begin(), node_durations.end(), permutation);
extractor::files::writeEdgeBasedNodeWeightsDurations(
config.GetPath(".osrm.enw"), node_weights, node_durations);
util::inplacePermutation(node_distances.begin(), node_distances.end(), permutation);
extractor::files::writeEdgeBasedNodeWeightsDurationsDistances(
config.GetPath(".osrm.enw"), node_weights, node_durations, node_distances);
}
{
const auto &filename = config.GetPath(".osrm.maneuver_overrides");
+5
View File
@@ -56,6 +56,11 @@ std::string getWrongOptionHelp(const engine::api::TableParameters &parameters)
help = "Number of coordinates needs to be at least two.";
}
if (parameters.fallback_speed < 0)
{
help = "fallback_speed must be > 0";
}
return help;
}
} // anon. ns
+88 -73
View File
@@ -44,32 +44,15 @@ namespace
{
using Monitor = SharedMonitor<SharedRegionRegister>;
void readBlocks(const boost::filesystem::path &path, DataLayout &layout)
{
tar::FileReader reader(path, tar::FileReader::VerifyFingerprint);
std::vector<tar::FileReader::FileEntry> entries;
reader.List(std::back_inserter(entries));
for (const auto &entry : entries)
{
const auto name_end = entry.name.rfind(".meta");
if (name_end == std::string::npos)
{
auto number_of_elements = reader.ReadElementCount64(entry.name);
layout.SetBlock(entry.name, Block{number_of_elements, entry.size});
}
}
}
struct RegionHandle
{
std::unique_ptr<SharedMemory> memory;
char *data_ptr;
std::uint8_t shm_key;
std::uint16_t shm_key;
};
auto setupRegion(SharedRegionRegister &shared_register, const DataLayout &layout)
RegionHandle setupRegion(SharedRegionRegister &shared_register,
const storage::BaseDataLayout &layout)
{
// This is safe because we have an exclusive lock for all osrm-datastore processes.
auto shm_key = shared_register.ReserveKey();
@@ -184,6 +167,24 @@ bool swapData(Monitor &monitor,
}
}
void populateLayoutFromFile(const boost::filesystem::path &path, storage::BaseDataLayout &layout)
{
tar::FileReader reader(path, tar::FileReader::VerifyFingerprint);
std::vector<tar::FileReader::FileEntry> entries;
reader.List(std::back_inserter(entries));
for (const auto &entry : entries)
{
const auto name_end = entry.name.rfind(".meta");
if (name_end == std::string::npos)
{
auto number_of_elements = reader.ReadElementCount64(entry.name);
layout.SetBlock(entry.name, Block{number_of_elements, entry.size, entry.offset});
}
}
}
Storage::Storage(StorageConfig config_) : config(std::move(config_)) {}
int Storage::Run(int max_wait, const std::string &dataset_name, bool only_metric)
@@ -243,29 +244,35 @@ int Storage::Run(int max_wait, const std::string &dataset_name, bool only_metric
auto static_region = shared_register.GetRegion(region_id);
auto static_memory = makeSharedMemory(static_region.shm_key);
DataLayout static_layout;
std::unique_ptr<storage::BaseDataLayout> static_layout =
std::make_unique<storage::ContiguousDataLayout>();
io::BufferReader reader(reinterpret_cast<char *>(static_memory->Ptr()),
static_memory->Size());
serialization::read(reader, static_layout);
serialization::read(reader, *static_layout);
auto layout_size = reader.GetPosition();
auto *data_ptr = reinterpret_cast<char *>(static_memory->Ptr()) + layout_size;
regions.push_back({data_ptr, static_layout});
regions.push_back({data_ptr, std::move(static_layout)});
readonly_handles.push_back({std::move(static_memory), data_ptr, static_region.shm_key});
}
else
{
DataLayout static_layout;
PopulateStaticLayout(static_layout);
auto static_handle = setupRegion(shared_register, static_layout);
regions.push_back({static_handle.data_ptr, static_layout});
std::unique_ptr<storage::BaseDataLayout> static_layout =
std::make_unique<storage::ContiguousDataLayout>();
Storage::PopulateLayoutWithRTree(*static_layout);
std::vector<std::pair<bool, boost::filesystem::path>> files = Storage::GetStaticFiles();
Storage::PopulateLayout(*static_layout, files);
auto static_handle = setupRegion(shared_register, *static_layout);
regions.push_back({static_handle.data_ptr, std::move(static_layout)});
handles[dataset_name + "/static"] = std::move(static_handle);
}
DataLayout updatable_layout;
PopulateUpdatableLayout(updatable_layout);
auto updatable_handle = setupRegion(shared_register, updatable_layout);
regions.push_back({updatable_handle.data_ptr, updatable_layout});
std::unique_ptr<storage::BaseDataLayout> updatable_layout =
std::make_unique<storage::ContiguousDataLayout>();
std::vector<std::pair<bool, boost::filesystem::path>> files = Storage::GetUpdatableFiles();
Storage::PopulateLayout(*updatable_layout, files);
auto updatable_handle = setupRegion(shared_register, *updatable_layout);
regions.push_back({updatable_handle.data_ptr, std::move(updatable_layout)});
handles[dataset_name + "/updatable"] = std::move(updatable_handle);
SharedDataIndex index{std::move(regions)};
@@ -281,24 +288,12 @@ int Storage::Run(int max_wait, const std::string &dataset_name, bool only_metric
return EXIT_SUCCESS;
}
/**
* This function examines all our data files and figures out how much
* memory needs to be allocated, and the position of each data structure
* in that big block. It updates the fields in the DataLayout parameter.
*/
void Storage::PopulateStaticLayout(DataLayout &static_layout)
std::vector<std::pair<bool, boost::filesystem::path>> Storage::GetStaticFiles()
{
{
auto absolute_file_index_path =
boost::filesystem::absolute(config.GetPath(".osrm.fileIndex"));
static_layout.SetBlock("/common/rtree/file_index_path",
make_block<char>(absolute_file_index_path.string().length() + 1));
}
constexpr bool REQUIRED = true;
constexpr bool OPTIONAL = false;
std::vector<std::pair<bool, boost::filesystem::path>> tar_files = {
std::vector<std::pair<bool, boost::filesystem::path>> files = {
{OPTIONAL, config.GetPath(".osrm.cells")},
{OPTIONAL, config.GetPath(".osrm.partition")},
{REQUIRED, config.GetPath(".osrm.icd")},
@@ -310,53 +305,73 @@ void Storage::PopulateStaticLayout(DataLayout &static_layout)
{REQUIRED, config.GetPath(".osrm.maneuver_overrides")},
{REQUIRED, config.GetPath(".osrm.edges")},
{REQUIRED, config.GetPath(".osrm.names")},
{REQUIRED, config.GetPath(".osrm.ramIndex")},
};
{REQUIRED, config.GetPath(".osrm.ramIndex")}};
for (const auto &file : tar_files)
for (const auto &file : files)
{
if (boost::filesystem::exists(file.second))
if (file.first == REQUIRED && !boost::filesystem::exists(file.second))
{
readBlocks(file.second, static_layout);
}
else
{
if (file.first == REQUIRED)
{
throw util::exception("Could not find required filed: " +
std::get<1>(file).string());
}
throw util::exception("Could not find required filed: " + std::get<1>(file).string());
}
}
return files;
}
void Storage::PopulateUpdatableLayout(DataLayout &updatable_layout)
std::vector<std::pair<bool, boost::filesystem::path>> Storage::GetUpdatableFiles()
{
constexpr bool REQUIRED = true;
constexpr bool OPTIONAL = false;
std::vector<std::pair<bool, boost::filesystem::path>> tar_files = {
std::vector<std::pair<bool, boost::filesystem::path>> files = {
{OPTIONAL, config.GetPath(".osrm.mldgr")},
{OPTIONAL, config.GetPath(".osrm.cell_metrics")},
{OPTIONAL, config.GetPath(".osrm.hsgr")},
{REQUIRED, config.GetPath(".osrm.datasource_names")},
{REQUIRED, config.GetPath(".osrm.geometry")},
{REQUIRED, config.GetPath(".osrm.turn_weight_penalties")},
{REQUIRED, config.GetPath(".osrm.turn_duration_penalties")},
};
{REQUIRED, config.GetPath(".osrm.turn_duration_penalties")}};
for (const auto &file : tar_files)
for (const auto &file : files)
{
if (file.first == REQUIRED && !boost::filesystem::exists(file.second))
{
throw util::exception("Could not find required filed: " + std::get<1>(file).string());
}
}
return files;
}
std::string Storage::PopulateLayoutWithRTree(storage::BaseDataLayout &layout)
{
// Figure out the path to the rtree file (it's not a tar file)
auto absolute_file_index_path = boost::filesystem::absolute(config.GetPath(".osrm.fileIndex"));
// Convert the boost::filesystem::path object into a plain string
// that can then be stored as a member of an allocator object
auto rtree_filename = absolute_file_index_path.string();
// Here, we hardcode the special file_index_path block name.
// The important bit here is that the "offset" is set to zero
layout.SetBlock("/common/rtree/file_index_path", make_block<char>(rtree_filename.length() + 1));
return rtree_filename;
}
/**
* This function examines all our data files and figures out how much
* memory needs to be allocated, and the position of each data structure
* in that big block. It updates the fields in the layout parameter.
*/
void Storage::PopulateLayout(storage::BaseDataLayout &layout,
const std::vector<std::pair<bool, boost::filesystem::path>> &files)
{
for (const auto &file : files)
{
if (boost::filesystem::exists(file.second))
{
readBlocks(file.second, updatable_layout);
}
else
{
if (file.first == REQUIRED)
{
throw util::exception("Could not find required filed: " +
std::get<1>(file).string());
}
populateLayoutFromFile(file.second, layout);
}
}
}
+13 -14
View File
@@ -70,8 +70,8 @@ std::istream &operator>>(std::istream &in, EngineConfig::Algorithm &algorithm)
throw util::RuntimeError(token, ErrorCode::UnknownAlgorithm, SOURCE_REF);
return in;
}
}
}
} // namespace engine
} // namespace osrm
// generate boost::program_options object for the routing part
inline unsigned generateServerProgramOptions(const int argc,
@@ -119,7 +119,10 @@ inline unsigned generateServerProgramOptions(const int argc,
"Load data from shared memory") //
("memory_file",
value<boost::filesystem::path>(&config.memory_file),
"Store data in a memory mapped file rather than in process memory.") //
"DEPRECATED: Will behave the same as --mmap.")(
"mmap,m",
value<bool>(&config.use_mmap)->implicit_value(true)->default_value(false),
"Map datafiles directly, do not use any additional memory.") //
("dataset-name",
value<std::string>(&config.dataset_name),
"Name of the shared memory dataset to connect to.") //
@@ -273,10 +276,12 @@ int main(int argc, const char *argv[]) try
#ifndef _WIN32
int sig = 0;
sigset_t new_mask;
sigset_t old_mask;
sigfillset(&new_mask);
pthread_sigmask(SIG_BLOCK, &new_mask, &old_mask);
sigset_t wait_mask;
sigemptyset(&wait_mask);
sigaddset(&wait_mask, SIGINT);
sigaddset(&wait_mask, SIGQUIT);
sigaddset(&wait_mask, SIGTERM);
pthread_sigmask(SIG_BLOCK, &wait_mask, nullptr); // only block necessary signals
#endif
auto service_handler = std::make_unique<server::ServiceHandler>(config);
@@ -298,19 +303,13 @@ int main(int argc, const char *argv[]) try
std::thread server_thread(std::move(server_task));
#ifndef _WIN32
sigset_t wait_mask;
pthread_sigmask(SIG_SETMASK, &old_mask, nullptr);
sigemptyset(&wait_mask);
sigaddset(&wait_mask, SIGINT);
sigaddset(&wait_mask, SIGQUIT);
sigaddset(&wait_mask, SIGTERM);
pthread_sigmask(SIG_BLOCK, &wait_mask, nullptr);
util::Log() << "running and waiting for requests";
if (std::getenv("SIGNAL_PARENT_WHEN_READY"))
{
kill(getppid(), SIGUSR1);
}
sigwait(&wait_mask, &sig);
util::Log() << "received signal " << sig;
#else
// Set console control handler to allow server to be stopped.
console_ctrl_function = std::bind(&server::Server::Stop, routing_server);
+6 -5
View File
@@ -52,14 +52,14 @@ void listRegions(bool show_blocks)
auto memory = makeSharedMemory(region.shm_key);
io::BufferReader reader(reinterpret_cast<char *>(memory->Ptr()), memory->Size());
DataLayout layout;
serialization::read(reader, layout);
std::unique_ptr<BaseDataLayout> layout = std::make_unique<ContiguousDataLayout>();
serialization::read(reader, *layout);
std::vector<std::string> block_names;
layout.List("", std::back_inserter(block_names));
layout->List("", std::back_inserter(block_names));
for (auto &name : block_names)
{
osrm::util::Log() << " " << name << " " << layout.GetBlockSize(name);
osrm::util::Log() << " " << name << " " << layout->GetBlockSize(name);
}
}
}
@@ -82,7 +82,8 @@ void springClean()
}
else
{
for (auto key : util::irange<std::uint8_t>(0, storage::SharedRegionRegister::MAX_SHM_KEYS))
for (auto key : util::irange<storage::SharedRegionRegister::RegionID>(
0, storage::SharedRegionRegister::MAX_SHM_KEYS))
{
deleteRegion(key);
}
+2 -7
View File
@@ -22,11 +22,6 @@ namespace coordinate_calculation
namespace
{
// earth radius varies between 6,356.750-6,378.135 km (3,949.901-3,963.189mi)
// The IUGG value for the equatorial radius is 6378.137 km (3963.19 miles)
const constexpr double EARTH_RADIUS = 6372797.560856;
class CheapRulerContainer
{
public:
@@ -117,7 +112,7 @@ double haversineDistance(const Coordinate coordinate_1, const Coordinate coordin
const double aharv = std::pow(std::sin(dlat / 2.0), 2.0) +
std::cos(dlat1) * std::cos(dlat2) * std::pow(std::sin(dlong / 2.), 2);
const double charv = 2. * std::atan2(std::sqrt(aharv), std::sqrt(1.0 - aharv));
return EARTH_RADIUS * charv;
return detail::EARTH_RADIUS * charv;
}
double greatCircleDistance(const Coordinate coordinate_1, const Coordinate coordinate_2)
@@ -138,7 +133,7 @@ double greatCircleDistance(const Coordinate coordinate_1, const Coordinate coord
const double x_value = (float_lon2 - float_lon1) * std::cos((float_lat1 + float_lat2) / 2.0);
const double y_value = float_lat2 - float_lat1;
return std::hypot(x_value, y_value) * EARTH_RADIUS;
return std::hypot(x_value, y_value) * detail::EARTH_RADIUS;
}
double perpendicularDistance(const Coordinate segment_source,
+32
View File
@@ -25,6 +25,28 @@ test('match: match in Monaco', function(assert) {
});
});
test('match: match in Monaco returning a buffer', function(assert) {
assert.plan(6);
var osrm = new OSRM(data_path);
var options = {
coordinates: three_test_coordinates,
timestamps: [1424684612, 1424684616, 1424684620]
};
osrm.match(options, { format: 'json_buffer' }, function(err, response) {
assert.ifError(err);
assert.ok(response instanceof Buffer);
response = JSON.parse(response);
assert.equal(response.matchings.length, 1);
assert.ok(response.matchings.every(function(m) {
return !!m.distance && !!m.duration && Array.isArray(m.legs) && !!m.geometry && m.confidence > 0;
}))
assert.equal(response.tracepoints.length, 3);
assert.ok(response.tracepoints.every(function(t) {
return !!t.hint && !isNaN(t.matchings_index) && !isNaN(t.waypoint_index) && !!t.name;
}));
});
});
test('match: match in Monaco without timestamps', function(assert) {
assert.plan(3);
var osrm = new OSRM(data_path);
@@ -225,6 +247,16 @@ test('match: throws on invalid tidy param', function(assert) {
/tidy must be of type Boolean/);
});
test('match: throws on invalid config param', function(assert) {
assert.plan(1);
var osrm = new OSRM({path: mld_data_path, algorithm: 'MLD'});
var options = {
coordinates: three_test_coordinates,
};
assert.throws(function() { osrm.match(options, { format: 'invalid' }, function(err, response) {}) },
/format must be a string:/);
});
test('match: match in Monaco without motorways', function(assert) {
assert.plan(3);
var osrm = new OSRM({path: mld_data_path, algorithm: 'MLD'});
+20 -1
View File
@@ -19,6 +19,21 @@ test('nearest', function(assert) {
});
});
test('nearest', function(assert) {
assert.plan(5);
var osrm = new OSRM(data_path);
osrm.nearest({
coordinates: [three_test_coordinates[0]]
}, { format: 'json_buffer' }, function(err, result) {
assert.ifError(err);
assert.ok(result instanceof Buffer);
result = JSON.parse(result);
assert.equal(result.waypoints.length, 1);
assert.equal(result.waypoints[0].location.length, 2);
assert.ok(result.waypoints[0].hasOwnProperty('name'));
});
});
test('nearest: can ask for multiple nearest pts', function(assert) {
assert.plan(2);
var osrm = new OSRM(data_path);
@@ -32,7 +47,7 @@ test('nearest: can ask for multiple nearest pts', function(assert) {
});
test('nearest: throws on invalid args', function(assert) {
assert.plan(6);
assert.plan(7);
var osrm = new OSRM(data_path);
var options = {};
assert.throws(function() { osrm.nearest(options); },
@@ -52,6 +67,10 @@ test('nearest: throws on invalid args', function(assert) {
options.number = 0;
assert.throws(function() { osrm.nearest(options, function(err, res) {}); },
/Number must be an integer greater than or equal to 1/);
options.number = 1;
assert.throws(function() { osrm.nearest(options, { format: 'invalid' }, function(err, res) {}); },
/format must be a string:/);
});
test('nearest: nearest in Monaco without motorways', function(assert) {
+17 -1
View File
@@ -43,8 +43,22 @@ test('route: routes Monaco on CoreCH', function(assert) {
});
});
test('route: routes Monaco and returns a JSON buffer', function(assert) {
assert.plan(6);
var osrm = new OSRM({path: monaco_corech_path, algorithm: 'CoreCH'});
osrm.route({coordinates: [[13.43864,52.51993],[13.415852,52.513191]]}, { format: 'json_buffer'}, function(err, result) {
assert.ifError(err);
assert.ok(result instanceof Buffer);
const route = JSON.parse(result);
assert.ok(route.waypoints);
assert.ok(route.routes);
assert.ok(route.routes.length);
assert.ok(route.routes[0].geometry);
});
});
test('route: throws with too few or invalid args', function(assert) {
assert.plan(3);
assert.plan(4);
var osrm = new OSRM(monaco_path);
assert.throws(function() { osrm.route({coordinates: two_test_coordinates}) },
/Two arguments required/);
@@ -52,6 +66,8 @@ test('route: throws with too few or invalid args', function(assert) {
/First arg must be an object/);
assert.throws(function() { osrm.route({coordinates: two_test_coordinates}, true)},
/last argument must be a callback function/);
assert.throws(function() { osrm.route({coordinates: two_test_coordinates}, { format: 'invalid' }, function(err, route) {})},
/format must be a string:/);
});
test('route: provides no alternatives by default, but when requested it may (not guaranteed)', function(assert) {
+33 -1
View File
@@ -48,6 +48,20 @@ test('table: test annotations paramater combination', function(assert) {
});
});
test('table: returns buffer', function(assert) {
assert.plan(3);
var osrm = new OSRM(data_path);
var options = {
coordinates: [three_test_coordinates[0], three_test_coordinates[1]],
};
osrm.table(options, { format: 'json_buffer' }, function(err, table) {
assert.ifError(err);
assert.ok(table instanceof Buffer);
table = JSON.parse(table);
assert.ok(table['durations'], 'distances table result should exist');
});
});
var tables = ['distances', 'durations'];
tables.forEach(function(annotation) {
@@ -116,7 +130,7 @@ tables.forEach(function(annotation) {
});
test('table: ' + annotation + ' throws on invalid arguments', function(assert) {
assert.plan(14);
assert.plan(15);
var osrm = new OSRM(data_path);
var options = {annotations: [annotation.slice(0,-1)]};
assert.throws(function() { osrm.table(options); },
@@ -135,6 +149,9 @@ tables.forEach(function(annotation) {
/Coordinates must be an array of \(lon\/lat\) pairs/);
options.coordinates = two_test_coordinates;
assert.throws(function() { osrm.table(options, { format: 'invalid' }, function(err, response) {}) },
/format must be a string:/);
options.sources = true;
assert.throws(function() { osrm.table(options, function(err, response) {}) },
/Sources must be an array of indices \(or undefined\)/);
@@ -228,5 +245,20 @@ tables.forEach(function(annotation) {
assert.equal(response[annotation].length, 2);
});
});
test('table: ' + annotation + ' table in Monaco with fallback speeds', function(assert) {
assert.plan(1);
var osrm = new OSRM({path: mld_data_path, algorithm: 'MLD'});
var options = {
coordinates: two_test_coordinates,
annotations: [annotation.slice(0,-1)],
fallback_speed: 1,
fallback_coordinate: 'input'
};
osrm.table(options, function(err, response) {
assert.equal(response[annotation].length, 2);
});
});
});
+16 -1
View File
@@ -17,6 +17,19 @@ test('trip: trip in Monaco', function(assert) {
});
});
test('trip: trip in Monaco as a buffer', function(assert) {
assert.plan(3);
var osrm = new OSRM(data_path);
osrm.trip({coordinates: two_test_coordinates}, { format: 'json_buffer' }, function(err, trip) {
assert.ifError(err);
assert.ok(trip instanceof Buffer);
trip = JSON.parse(trip);
for (t = 0; t < trip.trips.length; t++) {
assert.ok(trip.trips[t].geometry);
}
});
});
test('trip: trip with many locations in Monaco', function(assert) {
assert.plan(2);
@@ -33,12 +46,14 @@ test('trip: trip with many locations in Monaco', function(assert) {
});
test('trip: throws with too few or invalid args', function(assert) {
assert.plan(2);
assert.plan(3);
var osrm = new OSRM(data_path);
assert.throws(function() { osrm.trip({coordinates: two_test_coordinates}) },
/Two arguments required/);
assert.throws(function() { osrm.trip(null, function(err, trip) {}) },
/First arg must be an object/);
assert.throws(function() { osrm.trip({coordinates: two_test_coordinates}, { format: 'invalid' }, function(err, trip) {}) },
/format must be a string:/);
});
test('trip: throws with bad params', function(assert) {
@@ -17,7 +17,8 @@ bool operator!=(const QueryEdge &lhs, const QueryEdge &rhs) { return !(lhs == rh
std::ostream &operator<<(std::ostream &out, const QueryEdge::EdgeData &data)
{
out << "{" << data.turn_id << ", " << data.shortcut << ", " << data.duration << ", "
<< data.weight << ", " << data.forward << ", " << data.backward << "}";
<< data.distance << ", " << data.weight << ", " << data.forward << ", " << data.backward
<< "}";
return out;
}
@@ -36,31 +37,31 @@ BOOST_AUTO_TEST_CASE(merge_edge_of_multiple_graph)
ContractedEdgeContainer container;
std::vector<QueryEdge> edges;
edges.push_back(QueryEdge{0, 1, {1, false, 3, 6, true, false}});
edges.push_back(QueryEdge{1, 2, {2, false, 3, 6, true, false}});
edges.push_back(QueryEdge{2, 0, {3, false, 3, 6, false, true}});
edges.push_back(QueryEdge{2, 1, {4, false, 3, 6, false, true}});
edges.push_back(QueryEdge{0, 1, {1, false, 3, 3, 6, true, false}});
edges.push_back(QueryEdge{1, 2, {2, false, 3, 3, 6, true, false}});
edges.push_back(QueryEdge{2, 0, {3, false, 3, 3, 6, false, true}});
edges.push_back(QueryEdge{2, 1, {4, false, 3, 3, 6, false, true}});
container.Insert(edges);
edges.clear();
edges.push_back(QueryEdge{0, 1, {1, false, 3, 6, true, false}});
edges.push_back(QueryEdge{1, 2, {2, false, 3, 6, true, false}});
edges.push_back(QueryEdge{2, 0, {3, false, 12, 24, false, true}});
edges.push_back(QueryEdge{2, 1, {4, false, 12, 24, false, true}});
edges.push_back(QueryEdge{0, 1, {1, false, 3, 3, 6, true, false}});
edges.push_back(QueryEdge{1, 2, {2, false, 3, 3, 6, true, false}});
edges.push_back(QueryEdge{2, 0, {3, false, 12, 12, 24, false, true}});
edges.push_back(QueryEdge{2, 1, {4, false, 12, 12, 24, false, true}});
container.Merge(edges);
edges.clear();
edges.push_back(QueryEdge{1, 4, {5, false, 3, 6, true, false}});
edges.push_back(QueryEdge{1, 4, {5, false, 3, 3, 6, true, false}});
container.Merge(edges);
std::vector<QueryEdge> reference_edges;
reference_edges.push_back(QueryEdge{0, 1, {1, false, 3, 6, true, false}});
reference_edges.push_back(QueryEdge{1, 2, {2, false, 3, 6, true, false}});
reference_edges.push_back(QueryEdge{1, 4, {5, false, 3, 6, true, false}});
reference_edges.push_back(QueryEdge{2, 0, {3, false, 3, 6, false, true}});
reference_edges.push_back(QueryEdge{2, 0, {3, false, 12, 24, false, true}});
reference_edges.push_back(QueryEdge{2, 1, {4, false, 3, 6, false, true}});
reference_edges.push_back(QueryEdge{2, 1, {4, false, 12, 24, false, true}});
reference_edges.push_back(QueryEdge{0, 1, {1, false, 3, 3, 6, true, false}});
reference_edges.push_back(QueryEdge{1, 2, {2, false, 3, 3, 6, true, false}});
reference_edges.push_back(QueryEdge{1, 4, {5, false, 3, 3, 6, true, false}});
reference_edges.push_back(QueryEdge{2, 0, {3, false, 3, 3, 6, false, true}});
reference_edges.push_back(QueryEdge{2, 0, {3, false, 12, 12, 24, false, true}});
reference_edges.push_back(QueryEdge{2, 1, {4, false, 3, 3, 6, false, true}});
reference_edges.push_back(QueryEdge{2, 1, {4, false, 12, 12, 24, false, true}});
CHECK_EQUAL_COLLECTIONS(container.edges, reference_edges);
auto filters = container.MakeEdgeFilters();
@@ -78,22 +79,22 @@ BOOST_AUTO_TEST_CASE(merge_edge_of_multiple_disjoint_graph)
ContractedEdgeContainer container;
std::vector<QueryEdge> edges;
edges.push_back(QueryEdge{0, 1, {1, false, 3, 6, true, false}});
edges.push_back(QueryEdge{1, 2, {2, false, 3, 6, true, false}});
edges.push_back(QueryEdge{2, 0, {3, false, 12, 24, false, true}});
edges.push_back(QueryEdge{2, 1, {4, false, 12, 24, false, true}});
edges.push_back(QueryEdge{0, 1, {1, false, 3, 3, 6, true, false}});
edges.push_back(QueryEdge{1, 2, {2, false, 3, 3, 6, true, false}});
edges.push_back(QueryEdge{2, 0, {3, false, 12, 12, 24, false, true}});
edges.push_back(QueryEdge{2, 1, {4, false, 12, 12, 24, false, true}});
container.Merge(edges);
edges.clear();
edges.push_back(QueryEdge{1, 4, {5, false, 3, 6, true, false}});
edges.push_back(QueryEdge{1, 4, {5, false, 3, 3, 6, true, false}});
container.Merge(edges);
std::vector<QueryEdge> reference_edges;
reference_edges.push_back(QueryEdge{0, 1, {1, false, 3, 6, true, false}});
reference_edges.push_back(QueryEdge{1, 2, {2, false, 3, 6, true, false}});
reference_edges.push_back(QueryEdge{1, 4, {5, false, 3, 6, true, false}});
reference_edges.push_back(QueryEdge{2, 0, {3, false, 12, 24, false, true}});
reference_edges.push_back(QueryEdge{2, 1, {4, false, 12, 24, false, true}});
reference_edges.push_back(QueryEdge{0, 1, {1, false, 3, 3, 6, true, false}});
reference_edges.push_back(QueryEdge{1, 2, {2, false, 3, 3, 6, true, false}});
reference_edges.push_back(QueryEdge{1, 4, {5, false, 3, 3, 6, true, false}});
reference_edges.push_back(QueryEdge{2, 0, {3, false, 12, 12, 24, false, true}});
reference_edges.push_back(QueryEdge{2, 1, {4, false, 12, 12, 24, false, true}});
CHECK_EQUAL_COLLECTIONS(container.edges, reference_edges);
auto filters = container.MakeEdgeFilters();
+1 -1
View File
@@ -89,7 +89,7 @@ BOOST_AUTO_TEST_CASE(contract_graph)
reference_graph.DeleteEdgesTo(1, 3);
reference_graph.DeleteEdgesTo(4, 3);
// Insert shortcut
reference_graph.InsertEdge(4, 1, {2, 4, 3, 0, true, true, false});
reference_graph.InsertEdge(4, 1, {2, 4, 1.0, 3, 0, true, true, false});
/* After contracting 4:
*
+6 -2
View File
@@ -20,15 +20,19 @@ inline contractor::ContractorGraph makeGraph(const std::vector<TestEdge> &edges)
unsigned target;
int weight;
std::tie(start, target, weight) = edge;
int duration = weight * 2;
float distance = 1.0;
max_id = std::max(std::max(start, target), max_id);
input_edges.push_back(contractor::ContractorEdge{
start,
target,
contractor::ContractorEdgeData{weight, weight * 2, id++, 0, false, true, false}});
contractor::ContractorEdgeData{
weight, duration, distance, id++, 0, false, true, false}});
input_edges.push_back(contractor::ContractorEdge{
target,
start,
contractor::ContractorEdgeData{weight, weight * 2, id++, 0, false, false, true}});
contractor::ContractorEdgeData{
weight, duration, distance, id++, 0, false, false, true}});
}
std::sort(input_edges.begin(), input_edges.end());
+15 -2
View File
@@ -27,6 +27,7 @@ auto makeGraph(const MultiLevelPartition &mlp, const std::vector<MockEdge> &mock
{
EdgeWeight weight;
EdgeDuration duration;
EdgeDistance distance;
bool forward;
bool backward;
};
@@ -36,8 +37,20 @@ auto makeGraph(const MultiLevelPartition &mlp, const std::vector<MockEdge> &mock
for (const auto &m : mock_edges)
{
max_id = std::max<std::size_t>(max_id, std::max(m.start, m.target));
edges.push_back(Edge{m.start, m.target, m.weight, 2 * m.weight, true, false});
edges.push_back(Edge{m.target, m.start, m.weight, 2 * m.weight, false, true});
edges.push_back(Edge{m.start,
m.target,
m.weight,
2 * m.weight,
static_cast<EdgeDistance>(1.0),
true,
false});
edges.push_back(Edge{m.target,
m.start,
m.weight,
2 * m.weight,
static_cast<EdgeDistance>(1.0),
false,
true});
}
std::sort(edges.begin(), edges.end());
return partitioner::MultiLevelGraph<EdgeData, osrm::storage::Ownership::Container>(
@@ -31,6 +31,7 @@ inline InputEdge MakeUnitEdge(const NodeID from, const NodeID to)
to, // target
1, // weight
1, // duration
1, // distance
GeometryID{0, false}, // geometry_id
false, // reversed
NodeBasedEdgeClassification(), // default flags
@@ -47,6 +47,7 @@ BOOST_AUTO_TEST_CASE(simple_intersection_connectivity)
to,
1,
1,
1,
GeometryID{0, false},
!allowed,
NodeBasedEdgeClassification(),
@@ -174,6 +175,7 @@ BOOST_AUTO_TEST_CASE(roundabout_intersection_connectivity)
to,
1,
1,
1,
GeometryID{0, false},
!allowed,
NodeBasedEdgeClassification{
@@ -277,7 +279,7 @@ BOOST_AUTO_TEST_CASE(skip_degree_two_nodes)
//
const auto unit_edge = [](const NodeID from, const NodeID to, bool allowed) {
return InputEdge{
from, to, 1, 1, GeometryID{0, false}, !allowed, NodeBasedEdgeClassification{}, 0};
from, to, 1, 1, 1, GeometryID{0, false}, !allowed, NodeBasedEdgeClassification{}, 0};
};
std::vector<InputEdge> edges = {unit_edge(0, 1, true), // 0
unit_edge(1, 0, true),
+2 -2
View File
@@ -32,9 +32,9 @@ auto makeGraph(const std::vector<MockEdge> &mock_edges)
max_id = std::max<std::size_t>(max_id, std::max(m.start, m.target));
edges.push_back(InputEdge{
m.start, m.target, EdgeBasedGraphEdgeData{SPECIAL_NODEID, 1, 1, true, false}});
m.start, m.target, EdgeBasedGraphEdgeData{SPECIAL_NODEID, 1, 1, 1, true, false}});
edges.push_back(InputEdge{
m.target, m.start, EdgeBasedGraphEdgeData{SPECIAL_NODEID, 1, 1, false, true}});
m.target, m.start, EdgeBasedGraphEdgeData{SPECIAL_NODEID, 1, 1, 1, false, true}});
}
std::sort(edges.begin(), edges.end());
return DynamicEdgeBasedGraph(max_id + 1, edges);

Some files were not shown because too many files have changed in this diff Show More