itinero / routing

The routing core of itinero.
Apache License 2.0
222 stars 71 forks source link

[Exception resolving points with No- or Limited-Cache-Mode] Graph not sorted: Binary search using hilbert distance not possible #155

Closed goersen closed 6 years ago

goersen commented 6 years ago

Setup:

1. OSM-Data of germany (http://download.geofabrik.de/europe/germany-latest.osm.pbf)
2. Create a routerdb
3. Add contracted graph for Itinero.OSM.Vehicles.Vehicle.Car.Fastest() 
4. Save and reuse that routerdb for everything
5. When loading the routerDb use a limited-cache-profile like 'RouterDbProfile.MobileHighEnd' or 'RouterDbProfile.NoCache'
6. Running in a .NET Standard Library 2.0 (i.e. compatible with normal .Net Framework)
7. Tested on the latest prerelease (31)

Data:

Error:

Additional Info:

goersen commented 6 years ago

This issue can be closed. Seems to have occured due to wrong implementation.

xivk commented 6 years ago

Ok thanks! Any suggestion on making things clearer so this doesn't happen in the future?

goersen commented 6 years ago

Actually my previous comment sadly was too hasty :(. We refactored our routing structure and the exception didn't occur anymore. I figured the mess we had for initial testing & evaluation was responsible.

But then Non-negative number required. | Parameter name: count just popped up again. But at least I can pinpoint it now quite exact. This happens when:

1. Using a RouterDb with a limited-cache-profile
2. Using the same Router object for everything
3. Try to resolve points simultaneously on multiple threads
Disclaimer: The test I just ran for this tried to resolve the same points on both threads. I don't know if this is a factor in the issue.

When I wait for the first thread to be finished with resolving and moving into router.Calculate(...), before starting the second thread, both threads finish fine.

xivk commented 6 years ago

Ah ok, so it's possible when using the 'memory mapping' feature it's possible multithreading is an issue.

As a solution to this you can in this case have for example one router with it's own routerdb per thread where you open them individually using a new stream. But also there it will depend on your disk/OS if that will improve things AFAIK.

goersen commented 6 years ago

Thanks so much @xivk !

I think for now we'll build a wrapper for resolving points which synchronizes it and can also cache the RoutePoint-objects. This'll also help a bit with performance.

This also brings me to another question I have, but I don't want to open yet another issue bothering you:

The cache/no cache options put us a little bit into a dilemma.

This is with OSM-data of germany and on normal windows-machines (i.e. i7 3.4GHz, 8GB memory), not mobile devices.

My questions would be: a) Is this normal or are we using something wrong? b) Is there some workaround, middleground or anything? Maybe we could expand the cache-profiles or something?

xivk commented 6 years ago

To load everything in memory you leave the caching profile null. That is always fastest.

If startup time is important then you could load the RouterDb using RouterDbProfile.NoCache, it's ready instantly. Routing is fastest on mobile when having a contracted graph using RouterDbProfile.NoCache, haven't tested this on a regular machine but I'm guessing this would be best there too. This way you can start serving routes immediately, and in the background you load another RouterDb in memory and replace the NoCache one once it's loaded.

If RAM is the constraint then you're kind of stuck but there is room for improvement, for example, it is doable to only load the data that is crucial for the routing algorithm only and the meta-data using memory mapping. You can do this by customizing the caching profiles but you would also need to profile your service and look at where Itinero spends the most time.

xivk commented 6 years ago

Closing this issue, feel free to reopen if you have further questions.