set up for computing durations while unpacking them
copy dummy cache over implement retrievePackedPathFromSearchSpace calculate packed_path_from_source_to_middle debugging the retrievePackedPathFromSearchSpace function implementation adding in packed_path_from_source_to_middle cache is partway working unpack path and get duration that way the computeDurationForEdge method comment out cache clean up the code move vector creation and allocation to outside of loop hack to not return vectors on facade.GetUncompressedForwardDurations and facade.GetUncompressedReverseDurations clean up hack add exclude_index to cache key clearing cache with timestamp rebase against vectors->range pr swapped out unordered_map cache with a boost_lru implementation calculation for cache size cleaned up comment about cache size calculations unit tests cache uses unsigned char for exclude index clean up cache and unit tests pass in a hashed key to the threadlocal cache 500 mb threadlocal 2 t fixes and a rebase correct calculation
This commit is contained in:
parent
1a1293608d
commit
fbba23e66d
@ -25,6 +25,80 @@ Feature: Basic Distance Matrix
|
|||||||
Given the query options
|
Given the query options
|
||||||
| exclude | toll |
|
| exclude | toll |
|
||||||
|
|
||||||
|
Scenario: Testbot - Travel time matrix of minimal network with excludes
|
||||||
|
Given the query options
|
||||||
|
| exclude | toll |
|
||||||
|
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a b
|
||||||
|
c d
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | highway | toll | # |
|
||||||
|
| ab | motorway | | not drivable for exclude=motorway |
|
||||||
|
| cd | primary | | always drivable |
|
||||||
|
| ac | highway | yes | not drivable for exclude=motorway exclude=toll and exclude=motorway,toll |
|
||||||
|
| bd | highway | yes | not drivable for exclude=motorway exclude=toll |
|
||||||
|
|
||||||
|
When I request a travel time matrix I should get
|
||||||
|
| | a | b | c | d |
|
||||||
|
| a | 0 | 15 | | |
|
||||||
|
| b | 15 | 0 | | |
|
||||||
|
| c | | | 0 | 10 |
|
||||||
|
| d | | | 10 | 0 |
|
||||||
|
|
||||||
|
Scenario: Testbot - Travel time matrix of minimal network with different exclude
|
||||||
|
Given the query options
|
||||||
|
| exclude | motorway |
|
||||||
|
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a b
|
||||||
|
c d
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | highway | toll | # |
|
||||||
|
| ab | motorway | | not drivable for exclude=motorway |
|
||||||
|
| cd | primary | | always drivable |
|
||||||
|
| ac | highway | yes | not drivable for exclude=motorway exclude=toll and exclude=motorway,toll |
|
||||||
|
| bd | highway | yes | not drivable for exclude=motorway exclude=toll |
|
||||||
|
|
||||||
|
|
||||||
|
When I request a travel time matrix I should get
|
||||||
|
| | a | b | c | d |
|
||||||
|
| a | 0 | 40 | 15 | 25 |
|
||||||
|
| b | 40 | 0 | 25 | 15 |
|
||||||
|
| c | 15 | 25 | 0 | 10 |
|
||||||
|
| d | 25 | 15 | 10 | 0 |
|
||||||
|
|
||||||
|
Scenario: Testbot - Travel time matrix of minimal network with excludes combination
|
||||||
|
Given the query options
|
||||||
|
| exclude | motorway,toll |
|
||||||
|
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
a b
|
||||||
|
c d
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes | highway | toll | # |
|
||||||
|
| ab | motorway | | not drivable for exclude=motorway |
|
||||||
|
| cd | primary | | always drivable |
|
||||||
|
| ac | highway | yes | not drivable for exclude=motorway exclude=toll and exclude=motorway,toll |
|
||||||
|
| bd | highway | yes | not drivable for exclude=motorway exclude=toll |
|
||||||
|
|
||||||
|
When I request a travel time matrix I should get
|
||||||
|
| | a | b | c | d |
|
||||||
|
| a | 0 | 10 | 0 | 10 |
|
||||||
|
| b | 10 | 0 | 10 | 0 |
|
||||||
|
| c | 0 | 10 | 0 | 10 |
|
||||||
|
| d | 10 | 0 | 10 | 0 |
|
||||||
|
|
||||||
|
Scenario: Testbot - Travel time matrix with different way speeds
|
||||||
Given the node map
|
Given the node map
|
||||||
"""
|
"""
|
||||||
a b
|
a b
|
||||||
|
|||||||
@ -60,7 +60,8 @@ class DataWatchdogImpl<AlgorithmT, datafacade::ContiguousInternalMemoryDataFacad
|
|||||||
DataFacadeFactory<datafacade::ContiguousInternalMemoryDataFacade, AlgorithmT>(
|
DataFacadeFactory<datafacade::ContiguousInternalMemoryDataFacade, AlgorithmT>(
|
||||||
std::make_shared<datafacade::SharedMemoryAllocator>(
|
std::make_shared<datafacade::SharedMemoryAllocator>(
|
||||||
std::vector<storage::SharedRegionRegister::ShmKey>{
|
std::vector<storage::SharedRegionRegister::ShmKey>{
|
||||||
static_region.shm_key, updatable_region.shm_key}));
|
static_region.shm_key, updatable_region.shm_key}),
|
||||||
|
static_region.timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
watcher = std::thread(&DataWatchdogImpl::Run, this);
|
watcher = std::thread(&DataWatchdogImpl::Run, this);
|
||||||
@ -115,7 +116,8 @@ class DataWatchdogImpl<AlgorithmT, datafacade::ContiguousInternalMemoryDataFacad
|
|||||||
DataFacadeFactory<datafacade::ContiguousInternalMemoryDataFacade, AlgorithmT>(
|
DataFacadeFactory<datafacade::ContiguousInternalMemoryDataFacade, AlgorithmT>(
|
||||||
std::make_shared<datafacade::SharedMemoryAllocator>(
|
std::make_shared<datafacade::SharedMemoryAllocator>(
|
||||||
std::vector<storage::SharedRegionRegister::ShmKey>{
|
std::vector<storage::SharedRegionRegister::ShmKey>{
|
||||||
static_region.shm_key, updatable_region.shm_key}));
|
static_region.shm_key, updatable_region.shm_key}),
|
||||||
|
static_region.timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
util::Log() << "DataWatchdog thread stopped";
|
util::Log() << "DataWatchdog thread stopped";
|
||||||
|
|||||||
@ -168,6 +168,8 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade
|
|||||||
|
|
||||||
// allocator that keeps the allocation data
|
// allocator that keeps the allocation data
|
||||||
std::shared_ptr<ContiguousBlockAllocator> allocator;
|
std::shared_ptr<ContiguousBlockAllocator> allocator;
|
||||||
|
std::size_t m_exclude_index;
|
||||||
|
unsigned m_timestamp;
|
||||||
|
|
||||||
void InitializeInternalPointers(const storage::SharedDataIndex &index,
|
void InitializeInternalPointers(const storage::SharedDataIndex &index,
|
||||||
const std::string &metric_name,
|
const std::string &metric_name,
|
||||||
@ -183,6 +185,8 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade
|
|||||||
|
|
||||||
m_check_sum = *index.GetBlockPtr<std::uint32_t>("/common/connectivity_checksum");
|
m_check_sum = *index.GetBlockPtr<std::uint32_t>("/common/connectivity_checksum");
|
||||||
|
|
||||||
|
m_exclude_index = exclude_index;
|
||||||
|
|
||||||
std::tie(m_coordinate_list, m_osmnodeid_list) =
|
std::tie(m_coordinate_list, m_osmnodeid_list) =
|
||||||
make_nbn_data_view(index, "/common/nbn_data");
|
make_nbn_data_view(index, "/common/nbn_data");
|
||||||
|
|
||||||
@ -217,12 +221,16 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
std::size_t GetTimestamp() const { return m_timestamp; }
|
||||||
|
std::size_t GetExcludeIndex() const { return m_exclude_index; }
|
||||||
|
|
||||||
// allows switching between process_memory/shared_memory datafacade, based on the type of
|
// allows switching between process_memory/shared_memory datafacade, based on the type of
|
||||||
// allocator
|
// allocator
|
||||||
ContiguousInternalMemoryDataFacadeBase(std::shared_ptr<ContiguousBlockAllocator> allocator_,
|
ContiguousInternalMemoryDataFacadeBase(std::shared_ptr<ContiguousBlockAllocator> allocator_,
|
||||||
const std::string &metric_name,
|
const std::string &metric_name,
|
||||||
const std::size_t exclude_index)
|
const std::size_t exclude_index,
|
||||||
: allocator(std::move(allocator_))
|
unsigned timestamp)
|
||||||
|
: allocator(std::move(allocator_)), m_timestamp(timestamp)
|
||||||
{
|
{
|
||||||
InitializeInternalPointers(allocator->GetIndex(), metric_name, exclude_index);
|
InitializeInternalPointers(allocator->GetIndex(), metric_name, exclude_index);
|
||||||
}
|
}
|
||||||
@ -618,8 +626,9 @@ class ContiguousInternalMemoryDataFacade<CH>
|
|||||||
public:
|
public:
|
||||||
ContiguousInternalMemoryDataFacade(std::shared_ptr<ContiguousBlockAllocator> allocator,
|
ContiguousInternalMemoryDataFacade(std::shared_ptr<ContiguousBlockAllocator> allocator,
|
||||||
const std::string &metric_name,
|
const std::string &metric_name,
|
||||||
const std::size_t exclude_index)
|
const std::size_t exclude_index,
|
||||||
: ContiguousInternalMemoryDataFacadeBase(allocator, metric_name, exclude_index),
|
unsigned timestamp)
|
||||||
|
: ContiguousInternalMemoryDataFacadeBase(allocator, metric_name, exclude_index, timestamp),
|
||||||
ContiguousInternalMemoryAlgorithmDataFacade<CH>(allocator, metric_name, exclude_index)
|
ContiguousInternalMemoryAlgorithmDataFacade<CH>(allocator, metric_name, exclude_index)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -735,8 +744,9 @@ class ContiguousInternalMemoryDataFacade<MLD> final
|
|||||||
public:
|
public:
|
||||||
ContiguousInternalMemoryDataFacade(std::shared_ptr<ContiguousBlockAllocator> allocator,
|
ContiguousInternalMemoryDataFacade(std::shared_ptr<ContiguousBlockAllocator> allocator,
|
||||||
const std::string &metric_name,
|
const std::string &metric_name,
|
||||||
const std::size_t exclude_index)
|
const std::size_t exclude_index,
|
||||||
: ContiguousInternalMemoryDataFacadeBase(allocator, metric_name, exclude_index),
|
unsigned timestamp)
|
||||||
|
: ContiguousInternalMemoryDataFacadeBase(allocator, metric_name, exclude_index, timestamp),
|
||||||
ContiguousInternalMemoryAlgorithmDataFacade<MLD>(allocator, metric_name, exclude_index)
|
ContiguousInternalMemoryAlgorithmDataFacade<MLD>(allocator, metric_name, exclude_index)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,8 +30,8 @@ template <template <typename A> class FacadeT, typename AlgorithmT> class DataFa
|
|||||||
DataFacadeFactory() = default;
|
DataFacadeFactory() = default;
|
||||||
|
|
||||||
template <typename AllocatorT>
|
template <typename AllocatorT>
|
||||||
DataFacadeFactory(std::shared_ptr<AllocatorT> allocator)
|
DataFacadeFactory(std::shared_ptr<AllocatorT> allocator, unsigned timestamp)
|
||||||
: DataFacadeFactory(allocator, has_exclude_flags)
|
: DataFacadeFactory(allocator, has_exclude_flags, timestamp)
|
||||||
{
|
{
|
||||||
BOOST_ASSERT_MSG(facades.size() >= 1, "At least one datafacade is needed");
|
BOOST_ASSERT_MSG(facades.size() >= 1, "At least one datafacade is needed");
|
||||||
}
|
}
|
||||||
@ -44,7 +44,7 @@ template <template <typename A> class FacadeT, typename AlgorithmT> class DataFa
|
|||||||
private:
|
private:
|
||||||
// Algorithm with exclude flags
|
// Algorithm with exclude flags
|
||||||
template <typename AllocatorT>
|
template <typename AllocatorT>
|
||||||
DataFacadeFactory(std::shared_ptr<AllocatorT> allocator, std::true_type)
|
DataFacadeFactory(std::shared_ptr<AllocatorT> allocator, std::true_type, unsigned timestamp)
|
||||||
{
|
{
|
||||||
const auto &index = allocator->GetIndex();
|
const auto &index = allocator->GetIndex();
|
||||||
properties = index.template GetBlockPtr<extractor::ProfileProperties>("/common/properties");
|
properties = index.template GetBlockPtr<extractor::ProfileProperties>("/common/properties");
|
||||||
@ -71,7 +71,8 @@ template <template <typename A> class FacadeT, typename AlgorithmT> class DataFa
|
|||||||
std::size_t index =
|
std::size_t index =
|
||||||
std::stoi(exclude_prefix.substr(index_begin + 1, exclude_prefix.size()));
|
std::stoi(exclude_prefix.substr(index_begin + 1, exclude_prefix.size()));
|
||||||
BOOST_ASSERT(index >= 0 && index < facades.size());
|
BOOST_ASSERT(index >= 0 && index < facades.size());
|
||||||
facades[index] = std::make_shared<const Facade>(allocator, metric_name, index);
|
facades[index] =
|
||||||
|
std::make_shared<const Facade>(allocator, metric_name, index, timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto index : util::irange<std::size_t>(0, properties->class_names.size()))
|
for (const auto index : util::irange<std::size_t>(0, properties->class_names.size()))
|
||||||
@ -86,12 +87,12 @@ template <template <typename A> class FacadeT, typename AlgorithmT> class DataFa
|
|||||||
|
|
||||||
// Algorithm without exclude flags
|
// Algorithm without exclude flags
|
||||||
template <typename AllocatorT>
|
template <typename AllocatorT>
|
||||||
DataFacadeFactory(std::shared_ptr<AllocatorT> allocator, std::false_type)
|
DataFacadeFactory(std::shared_ptr<AllocatorT> allocator, std::false_type, unsigned timestamp)
|
||||||
{
|
{
|
||||||
const auto &index = allocator->GetIndex();
|
const auto &index = allocator->GetIndex();
|
||||||
properties = index.template GetBlockPtr<extractor::ProfileProperties>("/common/properties");
|
properties = index.template GetBlockPtr<extractor::ProfileProperties>("/common/properties");
|
||||||
const auto &metric_name = properties->GetWeightName();
|
const auto &metric_name = properties->GetWeightName();
|
||||||
facades.push_back(std::make_shared<const Facade>(allocator, metric_name, 0));
|
facades.push_back(std::make_shared<const Facade>(allocator, metric_name, 0, timestamp));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<const Facade> Get(const api::TileParameters &, std::false_type) const
|
std::shared_ptr<const Facade> Get(const api::TileParameters &, std::false_type) const
|
||||||
|
|||||||
@ -34,7 +34,8 @@ class ExternalProvider final : public DataFacadeProvider<AlgorithmT, FacadeT>
|
|||||||
|
|
||||||
ExternalProvider(const storage::StorageConfig &config,
|
ExternalProvider(const storage::StorageConfig &config,
|
||||||
const boost::filesystem::path &memory_file)
|
const boost::filesystem::path &memory_file)
|
||||||
: facade_factory(std::make_shared<datafacade::MMapMemoryAllocator>(config, memory_file))
|
: facade_factory(std::make_shared<datafacade::MMapMemoryAllocator>(config, memory_file),
|
||||||
|
0) // is it ok to add timestamp as zero here?
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,7 +59,7 @@ class ImmutableProvider final : public DataFacadeProvider<AlgorithmT, FacadeT>
|
|||||||
using Facade = typename DataFacadeProvider<AlgorithmT, FacadeT>::Facade;
|
using Facade = typename DataFacadeProvider<AlgorithmT, FacadeT>::Facade;
|
||||||
|
|
||||||
ImmutableProvider(const storage::StorageConfig &config)
|
ImmutableProvider(const storage::StorageConfig &config)
|
||||||
: facade_factory(std::make_shared<datafacade::ProcessMemoryAllocator>(config))
|
: facade_factory(std::make_shared<datafacade::ProcessMemoryAllocator>(config), 0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -177,6 +177,7 @@ void annotatePath(const FacadeT &facade,
|
|||||||
const auto geometry_index = facade.GetGeometryIndex(node_id);
|
const auto geometry_index = facade.GetGeometryIndex(node_id);
|
||||||
get_segment_geometry(geometry_index);
|
get_segment_geometry(geometry_index);
|
||||||
|
|
||||||
|
|
||||||
BOOST_ASSERT(id_vector.size() > 0);
|
BOOST_ASSERT(id_vector.size() > 0);
|
||||||
BOOST_ASSERT(datasource_vector.size() > 0);
|
BOOST_ASSERT(datasource_vector.size() > 0);
|
||||||
BOOST_ASSERT(weight_vector.size() + 1 == id_vector.size());
|
BOOST_ASSERT(weight_vector.size() + 1 == id_vector.size());
|
||||||
@ -406,6 +407,7 @@ InternalRouteResult extractRoute(const DataFacade<AlgorithmT> &facade,
|
|||||||
return raw_route_data;
|
return raw_route_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <typename FacadeT> EdgeDistance computeEdgeDistance(const FacadeT &facade, NodeID node_id)
|
template <typename FacadeT> EdgeDistance computeEdgeDistance(const FacadeT &facade, NodeID node_id)
|
||||||
{
|
{
|
||||||
const auto geometry_index = facade.GetGeometryIndex(node_id);
|
const auto geometry_index = facade.GetGeometryIndex(node_id);
|
||||||
@ -422,6 +424,31 @@ template <typename FacadeT> EdgeDistance computeEdgeDistance(const FacadeT &faca
|
|||||||
return total_distance;
|
return total_distance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename FacadeT>
|
||||||
|
EdgeDuration computeEdgeDuration(const FacadeT &facade, NodeID node_id, NodeID turn_id)
|
||||||
|
{
|
||||||
|
const auto geometry_index = facade.GetGeometryIndex(node_id);
|
||||||
|
|
||||||
|
// datastructures to hold extracted data from geometry
|
||||||
|
EdgeDuration total_duration;
|
||||||
|
|
||||||
|
if (geometry_index.forward)
|
||||||
|
{
|
||||||
|
auto duration_range = facade.GetUncompressedForwardDurations(geometry_index.id);
|
||||||
|
total_duration = std::accumulate(duration_range.begin(), duration_range.end(), 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto duration_range = facade.GetUncompressedReverseDurations(geometry_index.id);
|
||||||
|
total_duration = std::accumulate(duration_range.begin(), duration_range.end(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto turn_duration = facade.GetDurationPenaltyForEdgeID(turn_id);
|
||||||
|
total_duration += turn_duration;
|
||||||
|
|
||||||
|
return total_duration;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace routing_algorithms
|
} // namespace routing_algorithms
|
||||||
} // namespace engine
|
} // namespace engine
|
||||||
} // namespace osrm
|
} // namespace osrm
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
#include "engine/datafacade.hpp"
|
#include "engine/datafacade.hpp"
|
||||||
#include "engine/routing_algorithms/routing_base.hpp"
|
#include "engine/routing_algorithms/routing_base.hpp"
|
||||||
#include "engine/search_engine_data.hpp"
|
#include "engine/search_engine_data.hpp"
|
||||||
|
#include "engine/unpacking_cache.hpp"
|
||||||
|
|
||||||
#include "util/typedefs.hpp"
|
#include "util/typedefs.hpp"
|
||||||
|
|
||||||
@ -287,11 +288,128 @@ void unpackPath(const DataFacade<Algorithm> &facade,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
template <typename BidirectionalIterator>
|
||||||
|
EdgeDistance calculateEBGNodeDuration(const DataFacade<Algorithm> &facade,
|
||||||
|
BidirectionalIterator packed_path_begin,
|
||||||
|
BidirectionalIterator packed_path_end,
|
||||||
|
UnpackingCache &unpacking_cache)
|
||||||
|
{
|
||||||
|
// Make sure we have at least something to unpack
|
||||||
|
if (packed_path_begin == packed_path_end ||
|
||||||
|
std::distance(packed_path_begin, packed_path_end) <= 1)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
std::stack<std::tuple<NodeID, NodeID, bool>> recursion_stack;
|
||||||
|
std::stack<EdgeDuration> duration_stack;
|
||||||
|
|
||||||
|
// We have to push the path in reverse order onto the stack because it's LIFO.
|
||||||
|
for (auto current = std::prev(packed_path_end); current != packed_path_begin;
|
||||||
|
current = std::prev(current))
|
||||||
|
{
|
||||||
|
recursion_stack.emplace(*std::prev(current), *current, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::tuple<NodeID, NodeID, bool> edge;
|
||||||
|
while (!recursion_stack.empty())
|
||||||
|
{
|
||||||
|
edge = recursion_stack.top();
|
||||||
|
recursion_stack.pop();
|
||||||
|
|
||||||
|
// Have we processed the edge before? tells us if we have values in the durations stack that
|
||||||
|
// we can add up
|
||||||
|
if (!std::get<2>(edge))
|
||||||
|
{ // haven't processed edge before, so process it in the body!
|
||||||
|
|
||||||
|
std::get<2>(edge) = true; // mark that this edge will now be processed
|
||||||
|
if (unpacking_cache.IsEdgeInCache(std::make_tuple(
|
||||||
|
std::get<0>(edge), std::get<1>(edge), facade.GetExcludeIndex())))
|
||||||
|
{
|
||||||
|
EdgeDuration duration = unpacking_cache.GetDuration(std::make_tuple(
|
||||||
|
std::get<0>(edge), std::get<1>(edge), facade.GetExcludeIndex()));
|
||||||
|
duration_stack.emplace(duration);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Look for an edge on the forward CH graph (.forward)
|
||||||
|
EdgeID smaller_edge_id =
|
||||||
|
facade.FindSmallestEdge(std::get<0>(edge),
|
||||||
|
std::get<1>(edge),
|
||||||
|
[](const auto &data) { return data.forward; });
|
||||||
|
|
||||||
|
// If we didn't find one there, the we might be looking at a part of the path that
|
||||||
|
// was found using the backward search. Here, we flip the node order (.second,
|
||||||
|
// .first) and only consider edges with the `.backward` flag.
|
||||||
|
if (SPECIAL_EDGEID == smaller_edge_id)
|
||||||
|
{
|
||||||
|
smaller_edge_id =
|
||||||
|
facade.FindSmallestEdge(std::get<1>(edge),
|
||||||
|
std::get<0>(edge),
|
||||||
|
[](const auto &data) { return data.backward; });
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we didn't find anything *still*, then something is broken and someone has
|
||||||
|
// called this function with bad values.
|
||||||
|
BOOST_ASSERT_MSG(smaller_edge_id != SPECIAL_EDGEID, "Invalid smaller edge ID");
|
||||||
|
|
||||||
|
const auto &data = facade.GetEdgeData(smaller_edge_id);
|
||||||
|
BOOST_ASSERT_MSG(data.weight != std::numeric_limits<EdgeWeight>::max(),
|
||||||
|
"edge weight invalid");
|
||||||
|
|
||||||
|
// If the edge is a shortcut, we need to add the two halfs to the stack.
|
||||||
|
if (data.shortcut)
|
||||||
|
{ // unpack
|
||||||
|
const NodeID middle_node_id = data.turn_id;
|
||||||
|
// Note the order here - we're adding these to a stack, so we
|
||||||
|
// want the first->middle to get visited before middle->second
|
||||||
|
recursion_stack.emplace(edge);
|
||||||
|
recursion_stack.emplace(middle_node_id, std::get<1>(edge), false);
|
||||||
|
recursion_stack.emplace(std::get<0>(edge), middle_node_id, false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto temp = std::make_tuple(
|
||||||
|
std::get<0>(edge), std::get<1>(edge), facade.GetExcludeIndex());
|
||||||
|
// compute the duration here and put it onto the duration stack using method
|
||||||
|
// similar to annotatePath but smaller
|
||||||
|
EdgeDuration duration =
|
||||||
|
computeEdgeDuration(facade, std::get<0>(edge), data.turn_id);
|
||||||
|
duration_stack.emplace(duration);
|
||||||
|
unpacking_cache.AddEdge(temp, duration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ // the edge has already been processed. this means that there are enough values in the
|
||||||
|
// durations stack
|
||||||
|
BOOST_ASSERT_MSG(duration_stack.size() >= 2,
|
||||||
|
"There are not enough (at least 2) values on the duration stack");
|
||||||
|
EdgeDuration edge1 = duration_stack.top();
|
||||||
|
duration_stack.pop();
|
||||||
|
EdgeDuration edge2 = duration_stack.top();
|
||||||
|
duration_stack.pop();
|
||||||
|
EdgeDuration duration = edge1 + edge2;
|
||||||
|
duration_stack.emplace(duration);
|
||||||
|
unpacking_cache.AddEdge(
|
||||||
|
std::make_tuple(std::get<0>(edge), std::get<1>(edge), facade.GetExcludeIndex()),
|
||||||
|
duration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EdgeDuration total_duration = 0;
|
||||||
|
while (!duration_stack.empty())
|
||||||
|
{
|
||||||
|
total_duration += duration_stack.top();
|
||||||
|
duration_stack.pop();
|
||||||
|
}
|
||||||
|
return total_duration;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
template <typename BidirectionalIterator>
|
template <typename BidirectionalIterator>
|
||||||
EdgeDistance calculateEBGNodeAnnotations(const DataFacade<Algorithm> &facade,
|
EdgeDistance calculateEBGNodeDistance(const DataFacade<Algorithm> &facade,
|
||||||
BidirectionalIterator packed_path_begin,
|
BidirectionalIterator packed_path_begin,
|
||||||
BidirectionalIterator packed_path_end)
|
BidirectionalIterator packed_path_end,
|
||||||
|
UnpackingCache &unpacking_cache)
|
||||||
{
|
{
|
||||||
// Make sure we have at least something to unpack
|
// Make sure we have at least something to unpack
|
||||||
if (packed_path_begin == packed_path_end ||
|
if (packed_path_begin == packed_path_end ||
|
||||||
@ -302,6 +420,7 @@ EdgeDistance calculateEBGNodeAnnotations(const DataFacade<Algorithm> &facade,
|
|||||||
std::stack<EdgeDistance> distance_stack;
|
std::stack<EdgeDistance> distance_stack;
|
||||||
// We have to push the path in reverse order onto the stack because it's LIFO.
|
// We have to push the path in reverse order onto the stack because it's LIFO.
|
||||||
for (auto current = std::prev(packed_path_end); current > packed_path_begin;
|
for (auto current = std::prev(packed_path_end); current > packed_path_begin;
|
||||||
|
|
||||||
current = std::prev(current))
|
current = std::prev(current))
|
||||||
{
|
{
|
||||||
recursion_stack.emplace(*std::prev(current), *current, false);
|
recursion_stack.emplace(*std::prev(current), *current, false);
|
||||||
@ -320,51 +439,65 @@ EdgeDistance calculateEBGNodeAnnotations(const DataFacade<Algorithm> &facade,
|
|||||||
|
|
||||||
std::get<2>(edge) = true; // mark that this edge will now be processed
|
std::get<2>(edge) = true; // mark that this edge will now be processed
|
||||||
|
|
||||||
// Look for an edge on the forward CH graph (.forward)
|
if (unpacking_cache.IsEdgeInCache(std::make_tuple(
|
||||||
EdgeID smaller_edge_id =
|
std::get<0>(edge), std::get<1>(edge), facade.GetExcludeIndex())))
|
||||||
facade.FindSmallestEdge(std::get<0>(edge), std::get<1>(edge), [](const auto &data) {
|
|
||||||
return data.forward;
|
|
||||||
});
|
|
||||||
|
|
||||||
// If we didn't find one there, the we might be looking at a part of the path that
|
|
||||||
// was found using the backward search. Here, we flip the node order (.second,
|
|
||||||
// .first) and only consider edges with the `.backward` flag.
|
|
||||||
if (SPECIAL_EDGEID == smaller_edge_id)
|
|
||||||
{
|
{
|
||||||
smaller_edge_id =
|
EdgeDuration distance = unpacking_cache.GetDistance(std::make_tuple(
|
||||||
facade.FindSmallestEdge(std::get<1>(edge),
|
std::get<0>(edge), std::get<1>(edge), facade.GetExcludeIndex()));
|
||||||
std::get<0>(edge),
|
distance_stack.emplace(distance);
|
||||||
[](const auto &data) { return data.backward; });
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we didn't find anything *still*, then something is broken and someone has
|
|
||||||
// called this function with bad values.
|
|
||||||
BOOST_ASSERT_MSG(smaller_edge_id != SPECIAL_EDGEID, "Invalid smaller edge ID");
|
|
||||||
|
|
||||||
const auto &data = facade.GetEdgeData(smaller_edge_id);
|
|
||||||
BOOST_ASSERT_MSG(data.weight != std::numeric_limits<EdgeWeight>::max(),
|
|
||||||
"edge weight invalid");
|
|
||||||
|
|
||||||
// If the edge is a shortcut, we need to add the two halfs to the stack.
|
|
||||||
if (data.shortcut)
|
|
||||||
{ // unpack
|
|
||||||
const NodeID middle_node_id = data.turn_id;
|
|
||||||
// Note the order here - we're adding these to a stack, so we
|
|
||||||
// want the first->middle to get visited before middle->second
|
|
||||||
recursion_stack.emplace(edge);
|
|
||||||
recursion_stack.emplace(middle_node_id, std::get<1>(edge), false);
|
|
||||||
recursion_stack.emplace(std::get<0>(edge), middle_node_id, false);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// compute the duration here and put it onto the duration stack using method
|
// Look for an edge on the forward CH graph (.forward)
|
||||||
// similar to annotatePath but smaller
|
EdgeID smaller_edge_id =
|
||||||
EdgeDistance distance = computeEdgeDistance(facade, std::get<0>(edge));
|
facade.FindSmallestEdge(std::get<0>(edge),
|
||||||
distance_stack.emplace(distance);
|
std::get<1>(edge),
|
||||||
|
[](const auto &data) { return data.forward; });
|
||||||
|
|
||||||
|
// If we didn't find one there, the we might be looking at a part of the path that
|
||||||
|
// was found using the backward search. Here, we flip the node order (.second,
|
||||||
|
// .first) and only consider edges with the `.backward` flag.
|
||||||
|
if (SPECIAL_EDGEID == smaller_edge_id)
|
||||||
|
{
|
||||||
|
smaller_edge_id =
|
||||||
|
facade.FindSmallestEdge(std::get<1>(edge),
|
||||||
|
std::get<0>(edge),
|
||||||
|
[](const auto &data) { return data.backward; });
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we didn't find anything *still*, then something is broken and someone has
|
||||||
|
// called this function with bad values.
|
||||||
|
BOOST_ASSERT_MSG(smaller_edge_id != SPECIAL_EDGEID, "Invalid smaller edge ID");
|
||||||
|
|
||||||
|
const auto &data = facade.GetEdgeData(smaller_edge_id);
|
||||||
|
BOOST_ASSERT_MSG(data.weight != std::numeric_limits<EdgeWeight>::max(),
|
||||||
|
"edge weight invalid");
|
||||||
|
|
||||||
|
// If the edge is a shortcut, we need to add the two halfs to the stack.
|
||||||
|
if (data.shortcut)
|
||||||
|
{ // unpack
|
||||||
|
const NodeID middle_node_id = data.turn_id;
|
||||||
|
// Note the order here - we're adding these to a stack, so we
|
||||||
|
// want the first->middle to get visited before middle->second
|
||||||
|
recursion_stack.emplace(edge);
|
||||||
|
recursion_stack.emplace(middle_node_id, std::get<1>(edge), false);
|
||||||
|
recursion_stack.emplace(std::get<0>(edge), middle_node_id, false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto temp = std::make_tuple(
|
||||||
|
std::get<0>(edge), std::get<1>(edge), facade.GetExcludeIndex());
|
||||||
|
// compute the distance here and put it onto the distance stack using method
|
||||||
|
// similar to annotatePath but smaller
|
||||||
|
EdgeDistance distance = computeEdgeDistance(facade, std::get<0>(edge));
|
||||||
|
distance_stack.emplace(distance);
|
||||||
|
unpacking_cache.AddEdge(temp, distance);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{ // the edge has already been processed. this means that there are enough values in the
|
{
|
||||||
|
// the edge has already been processed. this means that there are enough values in the
|
||||||
// distances stack
|
// distances stack
|
||||||
|
|
||||||
BOOST_ASSERT_MSG(distance_stack.size() >= 2,
|
BOOST_ASSERT_MSG(distance_stack.size() >= 2,
|
||||||
@ -375,6 +508,9 @@ EdgeDistance calculateEBGNodeAnnotations(const DataFacade<Algorithm> &facade,
|
|||||||
distance_stack.pop();
|
distance_stack.pop();
|
||||||
EdgeDistance distance = distance1 + distance2;
|
EdgeDistance distance = distance1 + distance2;
|
||||||
distance_stack.emplace(distance);
|
distance_stack.emplace(distance);
|
||||||
|
unpacking_cache.AddEdge(
|
||||||
|
std::make_tuple(std::get<0>(edge), std::get<1>(edge), facade.GetExcludeIndex()),
|
||||||
|
distance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
#define SEARCH_ENGINE_DATA_HPP
|
#define SEARCH_ENGINE_DATA_HPP
|
||||||
|
|
||||||
#include "engine/algorithm.hpp"
|
#include "engine/algorithm.hpp"
|
||||||
|
#include "engine/unpacking_cache.hpp"
|
||||||
#include "util/query_heap.hpp"
|
#include "util/query_heap.hpp"
|
||||||
#include "util/typedefs.hpp"
|
#include "util/typedefs.hpp"
|
||||||
|
|
||||||
@ -46,6 +47,7 @@ template <> struct SearchEngineData<routing_algorithms::ch::Algorithm>
|
|||||||
|
|
||||||
using SearchEngineHeapPtr = boost::thread_specific_ptr<QueryHeap>;
|
using SearchEngineHeapPtr = boost::thread_specific_ptr<QueryHeap>;
|
||||||
using ManyToManyHeapPtr = boost::thread_specific_ptr<ManyToManyQueryHeap>;
|
using ManyToManyHeapPtr = boost::thread_specific_ptr<ManyToManyQueryHeap>;
|
||||||
|
using UnpackingCachePtr = boost::thread_specific_ptr<UnpackingCache>;
|
||||||
|
|
||||||
static SearchEngineHeapPtr forward_heap_1;
|
static SearchEngineHeapPtr forward_heap_1;
|
||||||
static SearchEngineHeapPtr reverse_heap_1;
|
static SearchEngineHeapPtr reverse_heap_1;
|
||||||
@ -54,6 +56,7 @@ template <> struct SearchEngineData<routing_algorithms::ch::Algorithm>
|
|||||||
static SearchEngineHeapPtr forward_heap_3;
|
static SearchEngineHeapPtr forward_heap_3;
|
||||||
static SearchEngineHeapPtr reverse_heap_3;
|
static SearchEngineHeapPtr reverse_heap_3;
|
||||||
static ManyToManyHeapPtr many_to_many_heap;
|
static ManyToManyHeapPtr many_to_many_heap;
|
||||||
|
static UnpackingCachePtr unpacking_cache;
|
||||||
|
|
||||||
void InitializeOrClearFirstThreadLocalStorage(unsigned number_of_nodes);
|
void InitializeOrClearFirstThreadLocalStorage(unsigned number_of_nodes);
|
||||||
|
|
||||||
@ -62,6 +65,8 @@ template <> struct SearchEngineData<routing_algorithms::ch::Algorithm>
|
|||||||
void InitializeOrClearThirdThreadLocalStorage(unsigned number_of_nodes);
|
void InitializeOrClearThirdThreadLocalStorage(unsigned number_of_nodes);
|
||||||
|
|
||||||
void InitializeOrClearManyToManyThreadLocalStorage(unsigned number_of_nodes);
|
void InitializeOrClearManyToManyThreadLocalStorage(unsigned number_of_nodes);
|
||||||
|
|
||||||
|
void InitializeOrClearUnpackingCacheThreadLocalStorage(unsigned timestamp);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MultiLayerDijkstraHeapData
|
struct MultiLayerDijkstraHeapData
|
||||||
|
|||||||
113
include/engine/unpacking_cache.hpp
Normal file
113
include/engine/unpacking_cache.hpp
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
#ifndef UNPACKING_CACHE_HPP
|
||||||
|
#define UNPACKING_CACHE_HPP
|
||||||
|
|
||||||
|
#include <boost/optional/optional_io.hpp>
|
||||||
|
#include <boost/thread.hpp>
|
||||||
|
|
||||||
|
#include "../../third_party/compute_detail/lru_cache.hpp"
|
||||||
|
#include "util/typedefs.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
// sizeof size_t: 8
|
||||||
|
// sizeof unsigned: 4
|
||||||
|
// sizeof unchar: 1
|
||||||
|
// sizeof uint32: 4
|
||||||
|
namespace osrm
|
||||||
|
{
|
||||||
|
namespace engine
|
||||||
|
{
|
||||||
|
typedef unsigned char ExcludeIndex;
|
||||||
|
typedef unsigned Timestamp;
|
||||||
|
typedef std::tuple<NodeID, NodeID, unsigned char> Key;
|
||||||
|
|
||||||
|
class UnpackingCache
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
boost::compute::detail::lru_cache<std::tuple<NodeID, NodeID, unsigned char>, EdgeDuration> m_cache;
|
||||||
|
unsigned m_current_data_timestamp = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// TO FIGURE OUT HOW MANY LINES TO INITIALIZE CACHE TO:
|
||||||
|
// Assume max cache size is 500mb (see bottom of OP here:
|
||||||
|
// https://github.com/Project-OSRM/osrm-backend/issues/4798#issue-288608332)
|
||||||
|
|
||||||
|
// LRU CACHE IMPLEMENTATION HAS THESE TWO STORAGE CONTAINERS
|
||||||
|
// Key is of size: std::uint32_t * 2 + (unsigned char) * 1
|
||||||
|
// = 4 * 2 + 1 * 1 = 9
|
||||||
|
// map: n * Key + n * EdgeDuration
|
||||||
|
// = n * 9 bytes + n * std::int32_t
|
||||||
|
// = n * 9 bytes + n * 4 bytes
|
||||||
|
// = n * 13 bytes
|
||||||
|
// list: n * Key
|
||||||
|
// = n * 9 bytes
|
||||||
|
// Total = n * (13 + 9) = n * 22 bytes
|
||||||
|
// Total cache size: 500 mb = 500 * 1024 *1024 bytes = 524288000 bytes
|
||||||
|
|
||||||
|
// THREAD LOCAL STORAGE (500 mb)
|
||||||
|
// Number of lines we need = 524288000 / 22 / number of threads = 23831272 / number of threads
|
||||||
|
// 16 threads: 23831272 / 16 = 1489454
|
||||||
|
// 8 threads: 23831272 / 8 = 2978909
|
||||||
|
// 4 threads: 23831272 / 4 = 5957818
|
||||||
|
// 2 threads: 23831272 / 2 = 11915636
|
||||||
|
|
||||||
|
// THREAD LOCAL STORAGE (1024 mb)
|
||||||
|
// Number of lines we need = 1073741824 / 22 / number of threads = 48806446 / number of threads
|
||||||
|
// 16 threads: 48806446 / 16 = 3050402
|
||||||
|
// 8 threads: 48806446 / 8 = 6100805
|
||||||
|
// 4 threads: 48806446 / 4 = 12201611
|
||||||
|
// 2 threads: 48806446 / 2 = 24403223
|
||||||
|
|
||||||
|
// LRU CACHE IMPLEMENTATION HAS THESE TWO STORAGE CONTAINERS
|
||||||
|
// Key is of size: std::uint32_t * 2 + (unsigned char) * 1 + unsigned * 1
|
||||||
|
// = 4 * 2 + 1 * 1 + 4 * 1 = 13
|
||||||
|
// map: n * Key + n * EdgeDuration
|
||||||
|
// = n * 13 bytes + n * std::int32_t
|
||||||
|
// = n * 13 bytes + n * 4 bytes
|
||||||
|
// = n * 17 bytes
|
||||||
|
// list: n * Key
|
||||||
|
// = n * 13 bytes
|
||||||
|
// Total = n * (17 + 13) = n * 30 bytes
|
||||||
|
// Total cache size: 500 mb = 500 * 1024 *1024 bytes = 524288000 bytes
|
||||||
|
// Total cache size: 1024 mb = 1024 * 1024 *1024 bytes = 1073741824 bytes
|
||||||
|
// Total cache size: 250 mb = 250 * 1024 *1024 bytes = 262144000 bytes
|
||||||
|
|
||||||
|
// SHARED STORAGE CACHE
|
||||||
|
// Number of lines for shared storage cache 1024 mb = 524288000 / 30 = 17476266
|
||||||
|
// Number of lines for shared storage cache 500 mb = 1073741824 / 30 = 35791394
|
||||||
|
// Number of lines for shared storage cache 250 mb = 262144000 / 30 = 8738133
|
||||||
|
|
||||||
|
|
||||||
|
UnpackingCache(unsigned timestamp) : m_cache(8738133), m_current_data_timestamp(timestamp){};
|
||||||
|
|
||||||
|
UnpackingCache(std::size_t cache_size, unsigned timestamp)
|
||||||
|
: m_cache(cache_size), m_current_data_timestamp(timestamp){};
|
||||||
|
|
||||||
|
void Clear(unsigned new_data_timestamp)
|
||||||
|
{
|
||||||
|
if (m_current_data_timestamp != new_data_timestamp)
|
||||||
|
{
|
||||||
|
m_cache.clear();
|
||||||
|
m_current_data_timestamp = new_data_timestamp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsEdgeInCache(std::tuple<NodeID, NodeID, unsigned char> edge)
|
||||||
|
{
|
||||||
|
return m_cache.contains(edge);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddEdge(std::tuple<NodeID, NodeID, unsigned char> edge, EdgeDuration duration)
|
||||||
|
{
|
||||||
|
m_cache.insert(edge, duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
EdgeDuration GetDuration(std::tuple<NodeID, NodeID, unsigned char> edge)
|
||||||
|
{
|
||||||
|
boost::optional<EdgeDuration> duration = m_cache.get(edge);
|
||||||
|
return duration ? *duration : MAXIMAL_EDGE_DURATION;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // engine
|
||||||
|
} // osrm
|
||||||
|
|
||||||
|
#endif // UNPACKING_CACHE_HPP
|
||||||
@ -335,6 +335,10 @@ manyToManySearch(SearchEngineData<ch::Algorithm> &engine_working_data,
|
|||||||
std::vector<NodeID> middle_nodes_table(number_of_entries, SPECIAL_NODEID);
|
std::vector<NodeID> middle_nodes_table(number_of_entries, SPECIAL_NODEID);
|
||||||
|
|
||||||
std::vector<NodeBucket> search_space_with_buckets;
|
std::vector<NodeBucket> search_space_with_buckets;
|
||||||
|
std::vector<NodeID> packed_leg;
|
||||||
|
|
||||||
|
engine_working_data.InitializeOrClearUnpackingCacheThreadLocalStorage(
|
||||||
|
facade.GetTimestamp()); // always pass in the timestamp and clear if it's different
|
||||||
|
|
||||||
// Populate buckets with paths from all accessible nodes to destinations via backward searches
|
// Populate buckets with paths from all accessible nodes to destinations via backward searches
|
||||||
for (std::uint32_t column_index = 0; column_index < target_indices.size(); ++column_index)
|
for (std::uint32_t column_index = 0; column_index < target_indices.size(); ++column_index)
|
||||||
|
|||||||
@ -14,6 +14,7 @@ SearchEngineData<CH>::SearchEngineHeapPtr SearchEngineData<CH>::reverse_heap_2;
|
|||||||
SearchEngineData<CH>::SearchEngineHeapPtr SearchEngineData<CH>::forward_heap_3;
|
SearchEngineData<CH>::SearchEngineHeapPtr SearchEngineData<CH>::forward_heap_3;
|
||||||
SearchEngineData<CH>::SearchEngineHeapPtr SearchEngineData<CH>::reverse_heap_3;
|
SearchEngineData<CH>::SearchEngineHeapPtr SearchEngineData<CH>::reverse_heap_3;
|
||||||
SearchEngineData<CH>::ManyToManyHeapPtr SearchEngineData<CH>::many_to_many_heap;
|
SearchEngineData<CH>::ManyToManyHeapPtr SearchEngineData<CH>::many_to_many_heap;
|
||||||
|
SearchEngineData<CH>::UnpackingCachePtr SearchEngineData<CH>::unpacking_cache;
|
||||||
|
|
||||||
void SearchEngineData<CH>::InitializeOrClearFirstThreadLocalStorage(unsigned number_of_nodes)
|
void SearchEngineData<CH>::InitializeOrClearFirstThreadLocalStorage(unsigned number_of_nodes)
|
||||||
{
|
{
|
||||||
@ -90,6 +91,18 @@ void SearchEngineData<CH>::InitializeOrClearManyToManyThreadLocalStorage(unsigne
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SearchEngineData<CH>::InitializeOrClearUnpackingCacheThreadLocalStorage(unsigned timestamp)
|
||||||
|
{
|
||||||
|
if (unpacking_cache.get())
|
||||||
|
{
|
||||||
|
unpacking_cache->Clear(timestamp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
unpacking_cache.reset(new UnpackingCache(timestamp));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// MLD
|
// MLD
|
||||||
using MLD = routing_algorithms::mld::Algorithm;
|
using MLD = routing_algorithms::mld::Algorithm;
|
||||||
SearchEngineData<MLD>::SearchEngineHeapPtr SearchEngineData<MLD>::forward_heap_1;
|
SearchEngineData<MLD>::SearchEngineHeapPtr SearchEngineData<MLD>::forward_heap_1;
|
||||||
|
|||||||
139
third_party/compute_detail/lru_cache.hpp
vendored
Normal file
139
third_party/compute_detail/lru_cache.hpp
vendored
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
//---------------------------------------------------------------------------//
|
||||||
|
// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com>
|
||||||
|
//
|
||||||
|
// Distributed under the Boost Software License, Version 1.0
|
||||||
|
// See accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
// http://www.boost.org/LICENSE_1_0.txt
|
||||||
|
//
|
||||||
|
// See http://boostorg.github.com/compute for more information.
|
||||||
|
//---------------------------------------------------------------------------//
|
||||||
|
|
||||||
|
#ifndef BOOST_COMPUTE_DETAIL_LRU_CACHE_HPP
|
||||||
|
#define BOOST_COMPUTE_DETAIL_LRU_CACHE_HPP
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <list>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include <boost/optional.hpp>
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
namespace compute {
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
// a cache which evicts the least recently used item when it is full
|
||||||
|
template<class Key, class Value>
|
||||||
|
class lru_cache
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef Key key_type;
|
||||||
|
typedef Value value_type;
|
||||||
|
typedef std::list<key_type> list_type;
|
||||||
|
typedef std::map<
|
||||||
|
key_type,
|
||||||
|
std::pair<value_type, typename list_type::iterator>
|
||||||
|
> map_type;
|
||||||
|
|
||||||
|
lru_cache(size_t capacity)
|
||||||
|
: m_capacity(capacity)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~lru_cache()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t size() const
|
||||||
|
{
|
||||||
|
return m_map.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t capacity() const
|
||||||
|
{
|
||||||
|
return m_capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool empty() const
|
||||||
|
{
|
||||||
|
return m_map.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool contains(const key_type &key)
|
||||||
|
{
|
||||||
|
return m_map.find(key) != m_map.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
void insert(const key_type &key, const value_type &value)
|
||||||
|
{
|
||||||
|
typename map_type::iterator i = m_map.find(key);
|
||||||
|
if(i == m_map.end()){
|
||||||
|
// insert item into the cache, but first check if it is full
|
||||||
|
if(size() >= m_capacity){
|
||||||
|
// cache is full, evict the least recently used item
|
||||||
|
evict();
|
||||||
|
}
|
||||||
|
|
||||||
|
// insert the new item
|
||||||
|
m_list.push_front(key);
|
||||||
|
m_map[key] = std::make_pair(value, m_list.begin());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::optional<value_type> get(const key_type &key)
|
||||||
|
{
|
||||||
|
// lookup value in the cache
|
||||||
|
typename map_type::iterator i = m_map.find(key);
|
||||||
|
if(i == m_map.end()){
|
||||||
|
// value not in cache
|
||||||
|
return boost::none;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return the value, but first update its place in the most
|
||||||
|
// recently used list
|
||||||
|
typename list_type::iterator j = i->second.second;
|
||||||
|
if(j != m_list.begin()){
|
||||||
|
// move item to the front of the most recently used list
|
||||||
|
m_list.erase(j);
|
||||||
|
m_list.push_front(key);
|
||||||
|
|
||||||
|
// update iterator in map
|
||||||
|
j = m_list.begin();
|
||||||
|
const value_type &value = i->second.first;
|
||||||
|
m_map[key] = std::make_pair(value, j);
|
||||||
|
|
||||||
|
// return the value
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// the item is already at the front of the most recently
|
||||||
|
// used list so just return it
|
||||||
|
return i->second.first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
m_map.clear();
|
||||||
|
m_list.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void evict()
|
||||||
|
{
|
||||||
|
// evict item from the end of most recently used list
|
||||||
|
typename list_type::iterator i = --m_list.end();
|
||||||
|
m_map.erase(*i);
|
||||||
|
m_list.erase(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
map_type m_map;
|
||||||
|
list_type m_list;
|
||||||
|
size_t m_capacity;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end detail namespace
|
||||||
|
} // end compute namespace
|
||||||
|
} // end boost namespace
|
||||||
|
|
||||||
|
#endif // BOOST_COMPUTE_DETAIL_LRU_CACHE_HPP
|
||||||
86
unit_tests/engine/unpacking_cache.cpp
Normal file
86
unit_tests/engine/unpacking_cache.cpp
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
#include "engine/unpacking_cache.hpp"
|
||||||
|
|
||||||
|
#include <boost/test/test_case_template.hpp>
|
||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <iterator>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_SUITE(unpacking_cache)
|
||||||
|
|
||||||
|
using namespace osrm;
|
||||||
|
using namespace osrm::engine;
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(add_edge_and_check_existence)
|
||||||
|
{
|
||||||
|
// Arrange (Setup)
|
||||||
|
unsigned timestamp = 1522782542;
|
||||||
|
UnpackingCache cache(1, timestamp);
|
||||||
|
|
||||||
|
auto key = std::make_tuple(1, 1, 1);
|
||||||
|
auto value = 1;
|
||||||
|
|
||||||
|
// Act
|
||||||
|
cache.AddEdge(key, value);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
BOOST_CHECK(cache.IsEdgeInCache(key) == true);
|
||||||
|
BOOST_CHECK(cache.IsEdgeInCache(std::make_tuple(2, 2, 2)) == false);
|
||||||
|
|
||||||
|
auto result = cache.GetDuration(key);
|
||||||
|
BOOST_CHECK_EQUAL(result, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(cache_invalidation)
|
||||||
|
{
|
||||||
|
// Arrange (Setup)
|
||||||
|
unsigned timestamp = 1522782542;
|
||||||
|
UnpackingCache cache(1, timestamp);
|
||||||
|
|
||||||
|
auto key1 = std::make_tuple(1, 1, 1);
|
||||||
|
auto value1 = 1;
|
||||||
|
|
||||||
|
auto key2 = std::make_tuple(2, 2, 2);
|
||||||
|
auto value2 = 2;
|
||||||
|
|
||||||
|
// Act
|
||||||
|
cache.AddEdge(key1, value1);
|
||||||
|
cache.AddEdge(key2, value2);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
auto result = cache.GetDuration(key1);
|
||||||
|
BOOST_CHECK_EQUAL(result, MAXIMAL_EDGE_DURATION);
|
||||||
|
|
||||||
|
result = cache.GetDuration(key2);
|
||||||
|
BOOST_CHECK_EQUAL(result, value2);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(new_data)
|
||||||
|
{
|
||||||
|
// Arrange (Setup)
|
||||||
|
unsigned timestamp1 = 1522782542;
|
||||||
|
unsigned timestamp2 = 1522782543;
|
||||||
|
|
||||||
|
UnpackingCache cache(1, timestamp1);
|
||||||
|
|
||||||
|
auto key1 = std::make_tuple(1, 2, 3);
|
||||||
|
auto value1 = 1;
|
||||||
|
auto key2 = std::make_tuple(2, 3, 4);
|
||||||
|
auto value2 = 2;
|
||||||
|
|
||||||
|
// Act
|
||||||
|
cache.AddEdge(key1, value1);
|
||||||
|
cache.Clear(timestamp2);
|
||||||
|
cache.AddEdge(key2, value2);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
BOOST_CHECK(cache.IsEdgeInCache(key1) == false);
|
||||||
|
BOOST_CHECK(cache.IsEdgeInCache(key2) == true);
|
||||||
|
BOOST_CHECK(cache.IsEdgeInCache(std::make_tuple(2, 2, 2)) == false);
|
||||||
|
|
||||||
|
auto result = cache.GetDuration(key2);
|
||||||
|
BOOST_CHECK_EQUAL(result, value2);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
Loading…
Reference in New Issue
Block a user