Skip to content
Laurent Gregoire edited this page Jul 19, 2011 · 25 revisions

[PageOutline]

Context

The default implementation of OTP uses a single graph to use within each webapp. If you want to have multiple planners you thus need to multiply the number of webapps. The "multiple graph" feature allows you to use multiple graphs within a single webapp. The multi-graph also support dynamic reload of graph data file upon changes.

opentripplanner-api-webapp configuration

Modify data-sources.xml as below:

<bean id="pathServiceFactory"

	class="org.opentripplanner.routing.impl.MultipleFilePathServiceFactoryImpl">

	<property name="pathPattern" value="/var/otp/graphs/{}" />

	<property name="subApplicationContextList">

		<list>

			<value>org/opentripplanner/api/application-context.xml</value>

		</list>

	</property>

	<property name="asyncReload" value="false" />

</bean>

Remove from org/opentripplanner/api/application-context.xml the following bean:

<bean id="pathServiceFactory" class="org.opentripplanner.routing.impl.SingletonPathServiceFactoryImpl">

	<property name="pathService" ref="pathService" />

</bean>

You have to remove the line <import resource="classpath:org/opentripplanner/api/application-context.xml" /> (see section How it works? to see why).

Modify the following options:

  • path to the various graphs (pathPattern option), with the special pattern "{}" acting as a placeholder for the router ID (more on this later);

  • asyncReload (more on this later).

Copy appropriate Graph.obj in the corresponding folders. In the example above it would be:

  • /var/otp/graphs/new-york/Graph.obj

  • /var/otp/graphs/portland/Graph.obj

  • ...

The routerID

The multigraph uses a specific router ID from the request to route to the corresponding router context/services (routerId parameter). The router ID is any string you want (provided it could be somehow translatable to a path). The config.js configuration file from opentripplanner-webapp contains a default empty value you can modify. It's up to the implementation to provide the correct router ID given the client context (list of router from a drop-down list box, value given as a URL parameter, different webapps or domains, etc...). One easy way is to dynamically generate config.js, filling-in the routerID parameter according to the request context.

Note: For now on the routerID is mandatory in the request in the multi-graph configuration. It has been suggested to use the from/to coordinates from a /plan request to automatically select the appropriate data. However this does not easily work for /metadata (where obviously no coordinates exists), neither for overlapping covered zones.

Dynamic reload of graph data

The multi-graph feature support the dynamic reload of graph data (the Graph.obj serialized file) upon change. At each request the application checks if the file has been modified, and reload it if necessary (blocking or not all requests depending on the asyncReload option, see below).

To update a graph, please make sure you use an atomic copy/move. There is an internal protection against non-atomic copy which may handle some situation (it retries a number of times in case of truncated file), but to be on the safe side, in production and/or automated scripting mode please use an atomic copy:

Note: You may want to use the multi-graph feature even if you have a single router context to use the dynamic reload feature. This is straightforward: either provide an empty/null routerID (the default value) with a pathPattern without any {}, or a fixed routerId.

asyncReload feature

If the data has been modified since it was loaded the last time, the new data will be updated by recreating a new context. For large data however, the loading process itself may take a long time for a user to deal with. The asyncReload option allows you to keep the old context until the new one is ready, to serve other requests made while the new one is loaded. Please note that in the worst case, this may require the double amount of RAM as two context will be present in memory at the same time. This can have a huge impact if you update all graph data in one go. In production scripts you can follow the following sequence if you use the asyncReload feature:

  • (If needed) Copy the new data to the same filesystem as the old data;

  • Atomically move/delete the new data over the old;

  • Immediately poll the planner (wget http://host.tld/webapp/ws/metadata?routerId=new-york) to force a reload and wait until it's done;

  • Process the next one.

This will ensure that 1) the blocking request which will reload the data will not be a user one; 2) you minimize the number of context present at the same time in RAM.

Context evinction

For now there is no option to evict from memory a previously loaded graph. The only solution is to force a webapp reload. It has been planned to add an admin webservice to do that.

How it works?

Note: this section is only of interest if you want to know how this works "under the hood".

OTP uses Spring to automatically generate the appropriate application context for the router to work with. By default, in "singleton" mode, web.xml includes data-sources.xml, which itself includes application-context.xml. They both provides appropriate context configuration for the single router instance. The location of the source file is given as a static configuration in the graphBundle bean.

In multi-graph mode, data-sources.xml does not automatically loads application-context.xml anymore. The application context is now given as a parameter to the pathServiceFactory bean (subApplicationContextList parameter). At startup, only data-sources.xml is loaded. It creates a single pathServiceFactory instance. When a new router context is requested, the factory will dynamically instantiate through Spring a new context, injecting dynamically a graphBundle bean with the appropriate graph data location. When the context is not needed anymore, it is dynamically destroyed, again through Spring, to liberate resources.

Clone this wiki locally