A Facade is an object that provides a simplified interface to a larger body to use. In OSRM, facade provide interfaces to upper layer and hide implementation details of data.
There are two major purpose for facade layer:
- Support different routing algorithm to calculate route, like
CH
,CRP
- Support different strategy to load data, such as load
all data into memory
, usemmap
to load, useshared memory
to load
You could read an abstract version of OSRM facade's design which contains a simplified version of OSRM facade. For more details about interface defined in facade please go to facade interface.
Facade provides the interface to retrieve data, for example, here is the code in routing_base_mld.hpp for how to use it:
template <bool DIRECTION, typename Algorithm, typename... Args>
void relaxOutgoingEdges(const DataFacade<Algorithm> &facade,
typename SearchEngineData<Algorithm>::QueryHeap &forward_heap,
const NodeID node,
const EdgeWeight weight,
Args... args)
{
const auto &partition = facade.GetMultiLevelPartition();
const auto &cells = facade.GetCellStorage();
const auto &metric = facade.GetCellMetric();
//...
// Boundary edges
for (const auto edge : facade.GetBorderEdgeRange(level, node))
{
const auto &edge_data = facade.GetEdgeData(edge);
if ((DIRECTION == FORWARD_DIRECTION) ? facade.IsForwardEdge(edge)
: facade.IsBackwardEdge(edge))
{
const NodeID to = facade.GetTarget(edge);
//...
}
BaseDataFacade
defines the interface to retrieve basic information, and ContiguousInternalMemoryDataFacadeBase
implements the interfaces.
For algorithm part, OSRM choose template specialization for the implementation. AlgorithmDataFacade
defines the basic type, AlgorithmDataFacade<CH>
and AlgorithmDataFacade<MLD>
are two specialization defines interfaces for supporting different algorithm, ContiguousInternalMemoryAlgorithmDataFacade<CH>
and ContiguousInternalMemoryAlgorithmDataFacade<MLD>
implements those two template separately.
In datafacade.hpp, you could find how they provide types for external usage:
For more information of interfaces' usage, you could come to this page: facade interface
Facade is the layer based on pre-processed OSRM data(extraction, contraction, partition, customization), to enable Facade's functionality it must load related data.
OSRM provides 3 ways to load data code link:
// method #1: Use shared memory to load data
// Shared memory is a way for inter process communication
// Which could used for multiple process visiting the same data
if (config.use_shared_memory)
{
util::Log(logDEBUG) << "Using shared memory with name \"" << config.dataset_name
<< "\" with algorithm " << routing_algorithms::name<Algorithm>();
facade_provider = std::make_unique<WatchingProvider<Algorithm>>(config.dataset_name);
}
// method #2: Use mmap to load data
// MMap loading is a efficient way to speed up initialization, actual data will be loaded
// only when needed.
else if (!config.memory_file.empty() || config.use_mmap)
{
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);
}
// method #3: Use process-local memory to load data
else
{
util::Log(logDEBUG) << "Using internal memory with algorithm "
<< routing_algorithms::name<Algorithm>();
facade_provider = std::make_unique<ImmutableProvider<Algorithm>>(config.storage_config);
}
Inside class Engine, there is a member variable facade_provider, depend on different config it will init facade_provider with different Provider. And different provider instancelized different memory allocator, so during engine's initialization it would use different strategy to init pointers which point to different data.
Class diagram
Sequence diagram