Only keep reader lock on shared memory during queries.
This commit is contained in:
parent
c69545c47a
commit
847f530c8e
@ -5,10 +5,11 @@
|
|||||||
|
|
||||||
#include "storage/shared_datatype.hpp"
|
#include "storage/shared_datatype.hpp"
|
||||||
#include "storage/shared_memory.hpp"
|
#include "storage/shared_memory.hpp"
|
||||||
|
#include "storage/shared_barriers.hpp"
|
||||||
|
|
||||||
#include <boost/interprocess/sync/named_upgradable_mutex.hpp>
|
#include <boost/interprocess/sync/named_upgradable_mutex.hpp>
|
||||||
#include <boost/thread/locks.hpp>
|
|
||||||
#include <boost/thread/lock_types.hpp>
|
#include <boost/thread/lock_types.hpp>
|
||||||
|
#include <boost/thread/locks.hpp>
|
||||||
#include <boost/thread/shared_mutex.hpp>
|
#include <boost/thread/shared_mutex.hpp>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@ -31,7 +32,7 @@ class DataWatchdog
|
|||||||
public:
|
public:
|
||||||
DataWatchdog()
|
DataWatchdog()
|
||||||
: shared_barriers{std::make_shared<storage::SharedBarriers>()},
|
: shared_barriers{std::make_shared<storage::SharedBarriers>()},
|
||||||
shared_regions(storage::makeSharedMemoryView(storage::CURRENT_REGIONS)),
|
shared_regions(storage::makeSharedMemory(storage::CURRENT_REGIONS)),
|
||||||
current_timestamp{storage::LAYOUT_NONE, storage::DATA_NONE, 0}
|
current_timestamp{storage::LAYOUT_NONE, storage::DATA_NONE, 0}
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -42,26 +43,13 @@ class DataWatchdog
|
|||||||
return storage::SharedMemory::RegionExists(storage::CURRENT_REGIONS);
|
return storage::SharedMemory::RegionExists(storage::CURRENT_REGIONS);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if it might be worth to try to aquire a exclusive lock
|
using RegionsLock =
|
||||||
bool HasNewRegion() const
|
boost::interprocess::sharable_lock<boost::interprocess::named_sharable_mutex>;
|
||||||
{
|
using LockAndFacade = std::pair<RegionsLock, std::shared_ptr<datafacade::BaseDataFacade>>;
|
||||||
const boost::interprocess::sharable_lock<boost::interprocess::named_upgradable_mutex> lock(
|
|
||||||
shared_barriers->current_regions_mutex);
|
|
||||||
|
|
||||||
const auto shared_timestamp =
|
|
||||||
static_cast<const storage::SharedDataTimestamp *>(shared_regions->Ptr());
|
|
||||||
|
|
||||||
// sanity check: if the timestamp is the same all other data needs to be the same as well
|
|
||||||
BOOST_ASSERT(shared_timestamp->timestamp != current_timestamp.timestamp ||
|
|
||||||
(shared_timestamp->layout == current_timestamp.layout &&
|
|
||||||
shared_timestamp->data == current_timestamp.data));
|
|
||||||
|
|
||||||
return shared_timestamp->timestamp != current_timestamp.timestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This will either update the contens of facade or just leave it as is
|
// This will either update the contens of facade or just leave it as is
|
||||||
// if the update was already done by another thread
|
// if the update was already done by another thread
|
||||||
void MaybeLoadNewRegion(std::shared_ptr<datafacade::BaseDataFacade> &facade)
|
LockAndFacade GetDataFacade()
|
||||||
{
|
{
|
||||||
const boost::interprocess::sharable_lock<boost::interprocess::named_upgradable_mutex> lock(
|
const boost::interprocess::sharable_lock<boost::interprocess::named_upgradable_mutex> lock(
|
||||||
shared_barriers->current_regions_mutex);
|
shared_barriers->current_regions_mutex);
|
||||||
@ -69,31 +57,55 @@ class DataWatchdog
|
|||||||
const auto shared_timestamp =
|
const auto shared_timestamp =
|
||||||
static_cast<const storage::SharedDataTimestamp *>(shared_regions->Ptr());
|
static_cast<const storage::SharedDataTimestamp *>(shared_regions->Ptr());
|
||||||
|
|
||||||
|
const auto get_locked_facade = [this, shared_timestamp]() {
|
||||||
|
if (current_timestamp.data == storage::DATA_1)
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(current_timestamp.layout == storage::LAYOUT_1);
|
||||||
|
return std::make_pair(RegionsLock(shared_barriers->regions_1_mutex), facade);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(current_timestamp.layout == storage::LAYOUT_2);
|
||||||
|
BOOST_ASSERT(current_timestamp.data == storage::DATA_2);
|
||||||
|
return std::make_pair(RegionsLock(shared_barriers->regions_2_mutex), facade);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// this blocks handle the common case when there is no data update -> we will only need a
|
||||||
|
// shared lock
|
||||||
|
{
|
||||||
|
boost::shared_lock<boost::shared_mutex> facade_lock(facade_mutex);
|
||||||
|
|
||||||
|
if (shared_timestamp->timestamp == current_timestamp.timestamp)
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(shared_timestamp->layout == current_timestamp.layout);
|
||||||
|
BOOST_ASSERT(shared_timestamp->data == current_timestamp.data);
|
||||||
|
return get_locked_facade();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we reach this code there is a data update to be made. multiple
|
||||||
|
// requests can reach this, but only ever one goes through at a time.
|
||||||
boost::upgrade_lock<boost::shared_mutex> facade_lock(facade_mutex);
|
boost::upgrade_lock<boost::shared_mutex> facade_lock(facade_mutex);
|
||||||
|
|
||||||
// if more then one request tried to aquire the write lock
|
|
||||||
// we might get overtaken before we actually do the writing
|
// we might get overtaken before we actually do the writing
|
||||||
// in that case we don't modify anthing
|
// in that case we don't modify anthing
|
||||||
if (shared_timestamp->timestamp == current_timestamp.timestamp)
|
if (shared_timestamp->timestamp == current_timestamp.timestamp)
|
||||||
{
|
{
|
||||||
BOOST_ASSERT(shared_timestamp->layout == current_timestamp.layout);
|
BOOST_ASSERT(shared_timestamp->layout == current_timestamp.layout);
|
||||||
BOOST_ASSERT(shared_timestamp->data == current_timestamp.data);
|
BOOST_ASSERT(shared_timestamp->data == current_timestamp.data);
|
||||||
}
|
|
||||||
// this thread has won and can update the data
|
|
||||||
else
|
|
||||||
{
|
|
||||||
boost::upgrade_to_unique_lock<boost::upgrade_mutex> unique_facade_lock(facade_lock);
|
|
||||||
|
|
||||||
current_timestamp = *shared_timestamp;
|
return get_locked_facade();
|
||||||
// TODO remove once we allow for more then one SharedMemoryFacade at the same time
|
|
||||||
// at this point no other query is allowed to reference this facade!
|
|
||||||
// the old facade will die exactly here
|
|
||||||
BOOST_ASSERT(!facade || facade.use_count() == 1);
|
|
||||||
facade = std::make_shared<datafacade::SharedDataFacade>(shared_barriers,
|
|
||||||
current_timestamp.layout,
|
|
||||||
current_timestamp.data,
|
|
||||||
current_timestamp.timestamp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// this thread has won and can update the data
|
||||||
|
boost::upgrade_to_unique_lock<boost::upgrade_mutex> unique_facade_lock(facade_lock);
|
||||||
|
|
||||||
|
current_timestamp = *shared_timestamp;
|
||||||
|
facade = std::make_shared<datafacade::SharedDataFacade>(
|
||||||
|
current_timestamp.layout, current_timestamp.data, current_timestamp.timestamp);
|
||||||
|
|
||||||
|
return get_locked_facade();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -105,6 +117,7 @@ class DataWatchdog
|
|||||||
std::unique_ptr<storage::SharedMemory> shared_regions;
|
std::unique_ptr<storage::SharedMemory> shared_regions;
|
||||||
|
|
||||||
mutable boost::shared_mutex facade_mutex;
|
mutable boost::shared_mutex facade_mutex;
|
||||||
|
std::shared_ptr<datafacade::SharedDataFacade> facade;
|
||||||
storage::SharedDataTimestamp current_timestamp;
|
storage::SharedDataTimestamp current_timestamp;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
// implements all data storage when shared memory _IS_ used
|
// implements all data storage when shared memory _IS_ used
|
||||||
|
|
||||||
#include "storage/shared_barriers.hpp"
|
|
||||||
#include "storage/shared_datatype.hpp"
|
#include "storage/shared_datatype.hpp"
|
||||||
#include "storage/shared_memory.hpp"
|
#include "storage/shared_memory.hpp"
|
||||||
#include "engine/datafacade/datafacade_base.hpp"
|
#include "engine/datafacade/datafacade_base.hpp"
|
||||||
@ -66,11 +65,9 @@ class SharedDataFacade final : public BaseDataFacade
|
|||||||
storage::SharedDataLayout *data_layout;
|
storage::SharedDataLayout *data_layout;
|
||||||
char *shared_memory;
|
char *shared_memory;
|
||||||
|
|
||||||
std::shared_ptr<storage::SharedBarriers> shared_barriers;
|
|
||||||
storage::SharedDataType layout_region;
|
storage::SharedDataType layout_region;
|
||||||
storage::SharedDataType data_region;
|
storage::SharedDataType data_region;
|
||||||
unsigned shared_timestamp;
|
unsigned shared_timestamp;
|
||||||
boost::interprocess::sharable_lock<boost::interprocess::named_sharable_mutex> regions_lock;
|
|
||||||
|
|
||||||
unsigned m_check_sum;
|
unsigned m_check_sum;
|
||||||
std::unique_ptr<QueryGraph> m_query_graph;
|
std::unique_ptr<QueryGraph> m_query_graph;
|
||||||
@ -384,26 +381,22 @@ class SharedDataFacade final : public BaseDataFacade
|
|||||||
public:
|
public:
|
||||||
virtual ~SharedDataFacade() {}
|
virtual ~SharedDataFacade() {}
|
||||||
|
|
||||||
SharedDataFacade(const std::shared_ptr<storage::SharedBarriers> &shared_barriers_,
|
SharedDataFacade(storage::SharedDataType layout_region_,
|
||||||
storage::SharedDataType layout_region_,
|
|
||||||
storage::SharedDataType data_region_,
|
storage::SharedDataType data_region_,
|
||||||
unsigned shared_timestamp_)
|
unsigned shared_timestamp_)
|
||||||
: shared_barriers(shared_barriers_),
|
: layout_region(layout_region_), data_region(data_region_),
|
||||||
layout_region(layout_region_), data_region(data_region_),
|
shared_timestamp(shared_timestamp_)
|
||||||
shared_timestamp(shared_timestamp_),
|
|
||||||
regions_lock(layout_region == storage::LAYOUT_1 ? shared_barriers->regions_1_mutex
|
|
||||||
: shared_barriers->regions_2_mutex)
|
|
||||||
{
|
{
|
||||||
util::SimpleLogger().Write(logDEBUG) << "Loading new data with shared timestamp "
|
util::SimpleLogger().Write(logDEBUG) << "Loading new data with shared timestamp "
|
||||||
<< shared_timestamp;
|
<< shared_timestamp;
|
||||||
|
|
||||||
BOOST_ASSERT(storage::SharedMemory::RegionExists(layout_region));
|
BOOST_ASSERT(storage::SharedMemory::RegionExists(layout_region));
|
||||||
m_layout_memory = storage::makeSharedMemoryView(layout_region);
|
m_layout_memory = storage::makeSharedMemory(layout_region);
|
||||||
|
|
||||||
data_layout = static_cast<storage::SharedDataLayout *>(m_layout_memory->Ptr());
|
data_layout = static_cast<storage::SharedDataLayout *>(m_layout_memory->Ptr());
|
||||||
|
|
||||||
BOOST_ASSERT(storage::SharedMemory::RegionExists(data_region));
|
BOOST_ASSERT(storage::SharedMemory::RegionExists(data_region));
|
||||||
m_large_memory = storage::makeSharedMemoryView(data_region);
|
m_large_memory = storage::makeSharedMemory(data_region);
|
||||||
shared_memory = (char *)(m_large_memory->Ptr());
|
shared_memory = (char *)(m_large_memory->Ptr());
|
||||||
|
|
||||||
LoadGraph();
|
LoadGraph();
|
||||||
|
@ -85,8 +85,9 @@ class Engine final
|
|||||||
std::unique_ptr<plugins::MatchPlugin> match_plugin;
|
std::unique_ptr<plugins::MatchPlugin> match_plugin;
|
||||||
std::unique_ptr<plugins::TilePlugin> tile_plugin;
|
std::unique_ptr<plugins::TilePlugin> tile_plugin;
|
||||||
|
|
||||||
// reading and setting this is protected by locking in the watchdog
|
// note in case of shared memory this will be empty, since the watchdog
|
||||||
mutable std::shared_ptr<datafacade::BaseDataFacade> query_data_facade;
|
// will provide us with the up-to-date facade
|
||||||
|
std::shared_ptr<datafacade::BaseDataFacade> immutable_data_facade;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -183,6 +183,29 @@ struct SharedDataTimestamp
|
|||||||
unsigned timestamp;
|
unsigned timestamp;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline std::string regionToString(const SharedDataType region)
|
||||||
|
{
|
||||||
|
switch (region)
|
||||||
|
{
|
||||||
|
case CURRENT_REGIONS:
|
||||||
|
return "CURRENT_REGIONS";
|
||||||
|
case LAYOUT_1:
|
||||||
|
return "LAYOUT_1";
|
||||||
|
case DATA_1:
|
||||||
|
return "DATA_1";
|
||||||
|
case LAYOUT_2:
|
||||||
|
return "LAYOUT_2";
|
||||||
|
case DATA_2:
|
||||||
|
return "DATA_2";
|
||||||
|
case LAYOUT_NONE:
|
||||||
|
return "LAYOUT_NONE";
|
||||||
|
case DATA_NONE:
|
||||||
|
return "DATA_NONE";
|
||||||
|
default:
|
||||||
|
return "INVALID_REGION";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static_assert(sizeof(block_id_to_name) / sizeof(*block_id_to_name) == SharedDataLayout::NUM_BLOCKS,
|
static_assert(sizeof(block_id_to_name) / sizeof(*block_id_to_name) == SharedDataLayout::NUM_BLOCKS,
|
||||||
"Number of blocks needs to match the number of Block names.");
|
"Number of blocks needs to match the number of Block names.");
|
||||||
}
|
}
|
||||||
|
@ -42,40 +42,6 @@ struct OSRMLockFile
|
|||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
class SharedMemory
|
class SharedMemory
|
||||||
{
|
{
|
||||||
|
|
||||||
// Remove shared memory on destruction
|
|
||||||
class shm_remove
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
int m_shmid;
|
|
||||||
|
|
||||||
public:
|
|
||||||
shm_remove() : m_shmid(INT_MAX) {}
|
|
||||||
shm_remove(int shmid) : m_shmid(shmid) {}
|
|
||||||
|
|
||||||
shm_remove(shm_remove &&other) : m_shmid(std::move(other.m_shmid)) {}
|
|
||||||
shm_remove(const shm_remove &) = delete;
|
|
||||||
shm_remove &operator=(const shm_remove &) = delete;
|
|
||||||
shm_remove &operator=(const shm_remove &&other)
|
|
||||||
{
|
|
||||||
m_shmid = other.m_shmid;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
~shm_remove()
|
|
||||||
{
|
|
||||||
if (m_shmid != INT_MAX)
|
|
||||||
{
|
|
||||||
util::SimpleLogger().Write(logDEBUG) << "automatic memory deallocation of "
|
|
||||||
<< m_shmid;
|
|
||||||
if (!boost::interprocess::xsi_shared_memory::remove(m_shmid))
|
|
||||||
{
|
|
||||||
util::SimpleLogger().Write(logDEBUG) << "could not deallocate id " << m_shmid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void *Ptr() const { return region.get_address(); }
|
void *Ptr() const { return region.get_address(); }
|
||||||
|
|
||||||
@ -86,28 +52,24 @@ class SharedMemory
|
|||||||
SharedMemory(const boost::filesystem::path &lock_file,
|
SharedMemory(const boost::filesystem::path &lock_file,
|
||||||
const IdentifierT id,
|
const IdentifierT id,
|
||||||
const uint64_t size = 0,
|
const uint64_t size = 0,
|
||||||
bool read_write = false,
|
bool read_write = false)
|
||||||
bool remove_prev = true,
|
|
||||||
bool owner = true)
|
|
||||||
: key(lock_file.string().c_str(), id)
|
: key(lock_file.string().c_str(), id)
|
||||||
{
|
{
|
||||||
|
const auto access =
|
||||||
|
read_write ? boost::interprocess::read_write : boost::interprocess::read_only;
|
||||||
|
// open only
|
||||||
if (0 == size)
|
if (0 == size)
|
||||||
{ // read_only
|
{
|
||||||
shm = boost::interprocess::xsi_shared_memory(boost::interprocess::open_only, key);
|
shm = boost::interprocess::xsi_shared_memory(boost::interprocess::open_only, key);
|
||||||
|
|
||||||
util::SimpleLogger().Write(logDEBUG) << "opening " << shm.get_shmid() << " from id "
|
util::SimpleLogger().Write(logDEBUG) << "opening " << shm.get_shmid() << " from id "
|
||||||
<< id;
|
<< id;
|
||||||
region = boost::interprocess::mapped_region(
|
|
||||||
shm,
|
region = boost::interprocess::mapped_region(shm, access);
|
||||||
(read_write ? boost::interprocess::read_write : boost::interprocess::read_only));
|
|
||||||
}
|
}
|
||||||
|
// open or create
|
||||||
else
|
else
|
||||||
{ // writeable pointer
|
{
|
||||||
// remove previously allocated mem
|
|
||||||
if (remove_prev)
|
|
||||||
{
|
|
||||||
Remove(key);
|
|
||||||
}
|
|
||||||
shm = boost::interprocess::xsi_shared_memory(
|
shm = boost::interprocess::xsi_shared_memory(
|
||||||
boost::interprocess::open_or_create, key, size);
|
boost::interprocess::open_or_create, key, size);
|
||||||
util::SimpleLogger().Write(logDEBUG) << "opening/creating " << shm.get_shmid()
|
util::SimpleLogger().Write(logDEBUG) << "opening/creating " << shm.get_shmid()
|
||||||
@ -121,12 +83,7 @@ class SharedMemory
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
region = boost::interprocess::mapped_region(shm, boost::interprocess::read_write);
|
region = boost::interprocess::mapped_region(shm, access);
|
||||||
|
|
||||||
if (owner)
|
|
||||||
{
|
|
||||||
remover = shm_remove{shm.get_shmid()};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,36 +118,28 @@ class SharedMemory
|
|||||||
{
|
{
|
||||||
boost::interprocess::xsi_shared_memory shm(boost::interprocess::open_only, key);
|
boost::interprocess::xsi_shared_memory shm(boost::interprocess::open_only, key);
|
||||||
}
|
}
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
result = false;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool Remove(const boost::interprocess::xsi_key &key)
|
|
||||||
{
|
|
||||||
bool ret = false;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
boost::interprocess::xsi_shared_memory xsi(boost::interprocess::open_only, key);
|
|
||||||
util::SimpleLogger().Write(logDEBUG) << "deallocating prev memory " << xsi.get_shmid();
|
|
||||||
ret = boost::interprocess::xsi_shared_memory::remove(xsi.get_shmid());
|
|
||||||
}
|
|
||||||
catch (const boost::interprocess::interprocess_exception &e)
|
catch (const boost::interprocess::interprocess_exception &e)
|
||||||
{
|
{
|
||||||
if (e.get_error_code() != boost::interprocess::not_found_error)
|
if (e.get_error_code() != boost::interprocess::not_found_error)
|
||||||
{
|
{
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
result = false;
|
||||||
}
|
}
|
||||||
return ret;
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool Remove(const boost::interprocess::xsi_key &key)
|
||||||
|
{
|
||||||
|
boost::interprocess::xsi_shared_memory xsi(boost::interprocess::open_only, key);
|
||||||
|
util::SimpleLogger().Write(logDEBUG) << "deallocating prev memory " << xsi.get_shmid();
|
||||||
|
return boost::interprocess::xsi_shared_memory::remove(xsi.get_shmid());
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::interprocess::xsi_key key;
|
boost::interprocess::xsi_key key;
|
||||||
boost::interprocess::xsi_shared_memory shm;
|
boost::interprocess::xsi_shared_memory shm;
|
||||||
boost::interprocess::mapped_region region;
|
boost::interprocess::mapped_region region;
|
||||||
shm_remove remover;
|
|
||||||
};
|
};
|
||||||
#else
|
#else
|
||||||
// Windows - specific code
|
// Windows - specific code
|
||||||
@ -198,31 +147,6 @@ class SharedMemory
|
|||||||
{
|
{
|
||||||
SharedMemory(const SharedMemory &) = delete;
|
SharedMemory(const SharedMemory &) = delete;
|
||||||
SharedMemory &operator=(const SharedMemory &) = delete;
|
SharedMemory &operator=(const SharedMemory &) = delete;
|
||||||
// Remove shared memory on destruction
|
|
||||||
class shm_remove
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
char *m_shmid;
|
|
||||||
|
|
||||||
public:
|
|
||||||
shm_remove() : m_shmid(nullptr) {}
|
|
||||||
shm_remove(char *id) : m_shmid(id) {}
|
|
||||||
|
|
||||||
shm_remove(const shm_remove &) = delete;
|
|
||||||
shm_remove &operator=(const shm_remove &) = delete;
|
|
||||||
|
|
||||||
~shm_remove()
|
|
||||||
{
|
|
||||||
if (m_shmid != nullptr)
|
|
||||||
{
|
|
||||||
util::SimpleLogger().Write(logDEBUG) << "automatic memory deallocation";
|
|
||||||
if (!boost::interprocess::shared_memory_object::remove(m_shmid))
|
|
||||||
{
|
|
||||||
util::SimpleLogger().Write(logDEBUG) << "could not deallocate id " << m_shmid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void *Ptr() const { return region.get_address(); }
|
void *Ptr() const { return region.get_address(); }
|
||||||
@ -230,36 +154,25 @@ class SharedMemory
|
|||||||
SharedMemory(const boost::filesystem::path &lock_file,
|
SharedMemory(const boost::filesystem::path &lock_file,
|
||||||
const int id,
|
const int id,
|
||||||
const uint64_t size = 0,
|
const uint64_t size = 0,
|
||||||
bool read_write = false,
|
bool read_write = false)
|
||||||
bool remove_prev = true,
|
|
||||||
bool owner = false)
|
|
||||||
{
|
{
|
||||||
sprintf(key, "%s.%d", "osrm.lock", id);
|
sprintf(key, "%s.%d", "osrm.lock", id);
|
||||||
|
auto access = read_write ? boost::interprocess::read_write : boost::interprocess::read_only;
|
||||||
if (0 == size)
|
if (0 == size)
|
||||||
{ // read_only
|
{ // read_only
|
||||||
shm = boost::interprocess::shared_memory_object(
|
shm = boost::interprocess::shared_memory_object(
|
||||||
boost::interprocess::open_only,
|
boost::interprocess::open_only,
|
||||||
key,
|
key,
|
||||||
read_write ? boost::interprocess::read_write : boost::interprocess::read_only);
|
read_write ? boost::interprocess::read_write : boost::interprocess::read_only);
|
||||||
region = boost::interprocess::mapped_region(
|
region = boost::interprocess::mapped_region(shm, access);
|
||||||
shm, read_write ? boost::interprocess::read_write : boost::interprocess::read_only);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{ // writeable pointer
|
{ // writeable pointer
|
||||||
// remove previously allocated mem
|
|
||||||
if (remove_prev)
|
|
||||||
{
|
|
||||||
Remove(key);
|
|
||||||
}
|
|
||||||
shm = boost::interprocess::shared_memory_object(
|
shm = boost::interprocess::shared_memory_object(
|
||||||
boost::interprocess::open_or_create, key, boost::interprocess::read_write);
|
boost::interprocess::open_or_create, key, boost::interprocess::read_write);
|
||||||
shm.truncate(size);
|
shm.truncate(size);
|
||||||
region = boost::interprocess::mapped_region(shm, boost::interprocess::read_write);
|
region = boost::interprocess::mapped_region(shm, access);
|
||||||
|
|
||||||
if (owner)
|
|
||||||
{
|
|
||||||
remover = shm_remover{key};
|
|
||||||
}
|
|
||||||
util::SimpleLogger().Write(logDEBUG) << "writeable memory allocated " << size
|
util::SimpleLogger().Write(logDEBUG) << "writeable memory allocated " << size
|
||||||
<< " bytes";
|
<< " bytes";
|
||||||
}
|
}
|
||||||
@ -308,35 +221,19 @@ class SharedMemory
|
|||||||
|
|
||||||
static bool Remove(char *key)
|
static bool Remove(char *key)
|
||||||
{
|
{
|
||||||
bool ret = false;
|
util::SimpleLogger().Write(logDEBUG) << "deallocating prev memory for key " << key;
|
||||||
try
|
return boost::interprocess::shared_memory_object::remove(key);
|
||||||
{
|
|
||||||
util::SimpleLogger().Write(logDEBUG) << "deallocating prev memory for key " << key;
|
|
||||||
ret = boost::interprocess::shared_memory_object::remove(key);
|
|
||||||
}
|
|
||||||
catch (const boost::interprocess::interprocess_exception &e)
|
|
||||||
{
|
|
||||||
if (e.get_error_code() != boost::interprocess::not_found_error)
|
|
||||||
{
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char key[500];
|
char key[500];
|
||||||
boost::interprocess::shared_memory_object shm;
|
boost::interprocess::shared_memory_object shm;
|
||||||
boost::interprocess::mapped_region region;
|
boost::interprocess::mapped_region region;
|
||||||
shm_remove remover;
|
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
template <typename IdentifierT, typename LockFileT = OSRMLockFile>
|
template <typename IdentifierT, typename LockFileT = OSRMLockFile>
|
||||||
std::unique_ptr<SharedMemory> makeSharedMemory(const IdentifierT &id,
|
std::unique_ptr<SharedMemory>
|
||||||
const uint64_t size = 0,
|
makeSharedMemory(const IdentifierT &id, const uint64_t size = 0, bool read_write = false)
|
||||||
bool read_write = false,
|
|
||||||
bool remove_prev = true,
|
|
||||||
bool owner = false)
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -352,8 +249,7 @@ std::unique_ptr<SharedMemory> makeSharedMemory(const IdentifierT &id,
|
|||||||
boost::filesystem::ofstream ofs(lock_file());
|
boost::filesystem::ofstream ofs(lock_file());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return std::make_unique<SharedMemory>(
|
return std::make_unique<SharedMemory>(lock_file(), id, size, read_write);
|
||||||
lock_file(), id, size, read_write, remove_prev, owner);
|
|
||||||
}
|
}
|
||||||
catch (const boost::interprocess::interprocess_exception &e)
|
catch (const boost::interprocess::interprocess_exception &e)
|
||||||
{
|
{
|
||||||
@ -362,17 +258,6 @@ std::unique_ptr<SharedMemory> makeSharedMemory(const IdentifierT &id,
|
|||||||
throw util::exception(e.what());
|
throw util::exception(e.what());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename IdentifierT>
|
|
||||||
std::unique_ptr<SharedMemory> makeSharedMemoryView(const IdentifierT &id)
|
|
||||||
{
|
|
||||||
return makeSharedMemory(id, 0, false, false, false);
|
|
||||||
}
|
|
||||||
template <typename IdentifierT>
|
|
||||||
std::unique_ptr<SharedMemory> makeOwnedSharedMemoryView(const IdentifierT &id)
|
|
||||||
{
|
|
||||||
return makeSharedMemory(id, 0, false, false, true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
#include "engine/engine.hpp"
|
|
||||||
#include "engine/api/route_parameters.hpp"
|
#include "engine/api/route_parameters.hpp"
|
||||||
|
#include "engine/data_watchdog.hpp"
|
||||||
|
#include "engine/engine.hpp"
|
||||||
#include "engine/engine_config.hpp"
|
#include "engine/engine_config.hpp"
|
||||||
#include "engine/status.hpp"
|
#include "engine/status.hpp"
|
||||||
#include "engine/data_watchdog.hpp"
|
|
||||||
|
|
||||||
#include "engine/plugins/match.hpp"
|
#include "engine/plugins/match.hpp"
|
||||||
#include "engine/plugins/nearest.hpp"
|
#include "engine/plugins/nearest.hpp"
|
||||||
@ -34,21 +34,23 @@ namespace
|
|||||||
// Abstracted away the query locking into a template function
|
// Abstracted away the query locking into a template function
|
||||||
// Works the same for every plugin.
|
// Works the same for every plugin.
|
||||||
template <typename ParameterT, typename PluginT, typename ResultT>
|
template <typename ParameterT, typename PluginT, typename ResultT>
|
||||||
osrm::engine::Status
|
osrm::engine::Status RunQuery(const std::unique_ptr<osrm::engine::DataWatchdog> &watchdog,
|
||||||
RunQuery(const std::unique_ptr<osrm::engine::DataWatchdog>& watchdog,
|
const std::shared_ptr<osrm::engine::datafacade::BaseDataFacade> &facade,
|
||||||
std::shared_ptr<osrm::engine::datafacade::BaseDataFacade> &facade,
|
const ParameterT ¶meters,
|
||||||
const ParameterT ¶meters,
|
PluginT &plugin,
|
||||||
PluginT &plugin,
|
ResultT &result)
|
||||||
ResultT &result)
|
|
||||||
{
|
{
|
||||||
if (watchdog && watchdog->HasNewRegion())
|
if (watchdog)
|
||||||
{
|
{
|
||||||
watchdog->MaybeLoadNewRegion(facade);
|
BOOST_ASSERT(!facade);
|
||||||
|
auto lock_and_facade = watchdog->GetDataFacade();
|
||||||
|
|
||||||
|
return plugin.HandleRequest(lock_and_facade.second, parameters, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
osrm::engine::Status status = plugin.HandleRequest(facade, parameters, result);
|
BOOST_ASSERT(facade);
|
||||||
|
|
||||||
return status;
|
return plugin.HandleRequest(facade, parameters, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // anon. ns
|
} // anon. ns
|
||||||
@ -71,10 +73,6 @@ Engine::Engine(const EngineConfig &config)
|
|||||||
}
|
}
|
||||||
|
|
||||||
watchdog = std::make_unique<DataWatchdog>();
|
watchdog = std::make_unique<DataWatchdog>();
|
||||||
// this will always either return a value or throw an exception
|
|
||||||
// in the initial run
|
|
||||||
watchdog->MaybeLoadNewRegion(query_data_facade);
|
|
||||||
BOOST_ASSERT(query_data_facade);
|
|
||||||
BOOST_ASSERT(watchdog);
|
BOOST_ASSERT(watchdog);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -83,7 +81,7 @@ Engine::Engine(const EngineConfig &config)
|
|||||||
{
|
{
|
||||||
throw util::exception("Invalid file paths given!");
|
throw util::exception("Invalid file paths given!");
|
||||||
}
|
}
|
||||||
query_data_facade = std::make_shared<datafacade::InternalDataFacade>(config.storage_config);
|
immutable_data_facade = std::make_shared<datafacade::InternalDataFacade>(config.storage_config);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register plugins
|
// Register plugins
|
||||||
@ -104,32 +102,32 @@ Engine &Engine::operator=(Engine &&) noexcept = default;
|
|||||||
|
|
||||||
Status Engine::Route(const api::RouteParameters ¶ms, util::json::Object &result) const
|
Status Engine::Route(const api::RouteParameters ¶ms, util::json::Object &result) const
|
||||||
{
|
{
|
||||||
return RunQuery(watchdog, query_data_facade, params, *route_plugin, result);
|
return RunQuery(watchdog, immutable_data_facade, params, *route_plugin, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
Status Engine::Table(const api::TableParameters ¶ms, util::json::Object &result) const
|
Status Engine::Table(const api::TableParameters ¶ms, util::json::Object &result) const
|
||||||
{
|
{
|
||||||
return RunQuery(watchdog, query_data_facade, params, *table_plugin, result);
|
return RunQuery(watchdog, immutable_data_facade, params, *table_plugin, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
Status Engine::Nearest(const api::NearestParameters ¶ms, util::json::Object &result) const
|
Status Engine::Nearest(const api::NearestParameters ¶ms, util::json::Object &result) const
|
||||||
{
|
{
|
||||||
return RunQuery(watchdog, query_data_facade, params, *nearest_plugin, result);
|
return RunQuery(watchdog, immutable_data_facade, params, *nearest_plugin, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
Status Engine::Trip(const api::TripParameters ¶ms, util::json::Object &result) const
|
Status Engine::Trip(const api::TripParameters ¶ms, util::json::Object &result) const
|
||||||
{
|
{
|
||||||
return RunQuery(watchdog, query_data_facade, params, *trip_plugin, result);
|
return RunQuery(watchdog, immutable_data_facade, params, *trip_plugin, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
Status Engine::Match(const api::MatchParameters ¶ms, util::json::Object &result) const
|
Status Engine::Match(const api::MatchParameters ¶ms, util::json::Object &result) const
|
||||||
{
|
{
|
||||||
return RunQuery(watchdog, query_data_facade, params, *match_plugin, result);
|
return RunQuery(watchdog, immutable_data_facade, params, *match_plugin, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
Status Engine::Tile(const api::TileParameters ¶ms, std::string &result) const
|
Status Engine::Tile(const api::TileParameters ¶ms, std::string &result) const
|
||||||
{
|
{
|
||||||
return RunQuery(watchdog, query_data_facade, params, *tile_plugin, result);
|
return RunQuery(watchdog, immutable_data_facade, params, *tile_plugin, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // engine ns
|
} // engine ns
|
||||||
|
@ -47,35 +47,6 @@ namespace osrm
|
|||||||
namespace storage
|
namespace storage
|
||||||
{
|
{
|
||||||
|
|
||||||
// delete a shared memory region. report warning if it could not be deleted
|
|
||||||
void deleteRegion(const SharedDataType region)
|
|
||||||
{
|
|
||||||
if (SharedMemory::RegionExists(region) && !SharedMemory::Remove(region))
|
|
||||||
{
|
|
||||||
const std::string name = [&] {
|
|
||||||
switch (region)
|
|
||||||
{
|
|
||||||
case CURRENT_REGIONS:
|
|
||||||
return "CURRENT_REGIONS";
|
|
||||||
case LAYOUT_1:
|
|
||||||
return "LAYOUT_1";
|
|
||||||
case DATA_1:
|
|
||||||
return "DATA_1";
|
|
||||||
case LAYOUT_2:
|
|
||||||
return "LAYOUT_2";
|
|
||||||
case DATA_2:
|
|
||||||
return "DATA_2";
|
|
||||||
case LAYOUT_NONE:
|
|
||||||
return "LAYOUT_NONE";
|
|
||||||
default: // DATA_NONE:
|
|
||||||
return "DATA_NONE";
|
|
||||||
}
|
|
||||||
}();
|
|
||||||
|
|
||||||
util::SimpleLogger().Write(logWARNING) << "could not delete shared memory region " << name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
using RTreeLeaf = engine::datafacade::BaseDataFacade::RTreeLeaf;
|
using RTreeLeaf = engine::datafacade::BaseDataFacade::RTreeLeaf;
|
||||||
using RTreeNode =
|
using RTreeNode =
|
||||||
util::StaticRTree<RTreeLeaf, util::ShM<util::Coordinate, true>::vector, true>::TreeNode;
|
util::StaticRTree<RTreeLeaf, util::ShM<util::Coordinate, true>::vector, true>::TreeNode;
|
||||||
@ -83,11 +54,33 @@ using QueryGraph = util::StaticGraph<contractor::QueryEdge::EdgeData>;
|
|||||||
|
|
||||||
Storage::Storage(StorageConfig config_) : config(std::move(config_)) {}
|
Storage::Storage(StorageConfig config_) : config(std::move(config_)) {}
|
||||||
|
|
||||||
bool regionsAvailable(SharedDataType layout, SharedDataType data)
|
struct RegionsLayout
|
||||||
{
|
{
|
||||||
auto shared_regions = makeSharedMemoryView(CURRENT_REGIONS);
|
SharedDataType current_layout_region;
|
||||||
const auto shared_timestamp = static_cast<const SharedDataTimestamp *>(shared_regions->Ptr());
|
SharedDataType current_data_region;
|
||||||
return shared_timestamp->layout != layout && shared_timestamp->data != data;
|
boost::interprocess::named_sharable_mutex ¤t_regions_mutex;
|
||||||
|
SharedDataType old_layout_region;
|
||||||
|
SharedDataType old_data_region;
|
||||||
|
boost::interprocess::named_sharable_mutex &old_regions_mutex;
|
||||||
|
};
|
||||||
|
|
||||||
|
RegionsLayout getRegionsLayout(SharedBarriers &barriers)
|
||||||
|
{
|
||||||
|
if (SharedMemory::RegionExists(CURRENT_REGIONS))
|
||||||
|
{
|
||||||
|
auto shared_regions = makeSharedMemory(CURRENT_REGIONS);
|
||||||
|
const auto shared_timestamp = static_cast<const SharedDataTimestamp *>(shared_regions->Ptr());
|
||||||
|
if (shared_timestamp->data == DATA_1)
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(shared_timestamp->layout == LAYOUT_1);
|
||||||
|
return RegionsLayout {LAYOUT_1, DATA_1, barriers.regions_1_mutex, LAYOUT_2, DATA_2, barriers.regions_2_mutex};
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_ASSERT(shared_timestamp->data == DATA_2);
|
||||||
|
BOOST_ASSERT(shared_timestamp->layout == LAYOUT_2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return RegionsLayout {LAYOUT_2, DATA_2, barriers.regions_2_mutex, LAYOUT_1, DATA_1, barriers.regions_1_mutex};
|
||||||
}
|
}
|
||||||
|
|
||||||
int Storage::Run()
|
int Storage::Run()
|
||||||
@ -124,36 +117,27 @@ int Storage::Run()
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const auto regions_1_available = regionsAvailable(LAYOUT_1, DATA_1);
|
auto regions_layout = getRegionsLayout(barriers);
|
||||||
const auto regions_2_available = regionsAvailable(LAYOUT_2, DATA_2);
|
const SharedDataType layout_region = regions_layout.old_layout_region;
|
||||||
|
const SharedDataType data_region = regions_layout.old_data_region;
|
||||||
|
|
||||||
const SharedDataType layout_region = [&] {
|
util::SimpleLogger().Write() << "Waiting for all queries on the old dataset to finish:";
|
||||||
if (regions_1_available)
|
boost::interprocess::scoped_lock<boost::interprocess::named_sharable_mutex>
|
||||||
{
|
layout_lock(regions_layout.old_regions_mutex);
|
||||||
return LAYOUT_1;
|
util::SimpleLogger().Write() << "Ok.";
|
||||||
}
|
|
||||||
if (regions_2_available)
|
|
||||||
{
|
|
||||||
return LAYOUT_2;
|
|
||||||
}
|
|
||||||
throw util::exception("No shared memory region free!");
|
|
||||||
}();
|
|
||||||
const SharedDataType data_region = [&] {
|
|
||||||
if (regions_1_available)
|
|
||||||
{
|
|
||||||
return DATA_1;
|
|
||||||
}
|
|
||||||
if (regions_2_available)
|
|
||||||
{
|
|
||||||
return DATA_2;
|
|
||||||
}
|
|
||||||
throw util::exception("No shared memory region free!");
|
|
||||||
}();
|
|
||||||
|
|
||||||
BOOST_ASSERT(regions_1_available || regions_2_available);
|
// since we can't change the size of a shared memory regions we delete and reallocate
|
||||||
|
if (SharedMemory::RegionExists(layout_region) && !SharedMemory::Remove(layout_region))
|
||||||
|
{
|
||||||
|
throw util::exception("Could not remove " + regionToString(layout_region));
|
||||||
|
}
|
||||||
|
if (SharedMemory::RegionExists(data_region) && !SharedMemory::Remove(data_region))
|
||||||
|
{
|
||||||
|
throw util::exception("Could not remove " + regionToString(data_region));
|
||||||
|
}
|
||||||
|
|
||||||
// Allocate a memory layout in shared memory, deallocate previous
|
// Allocate a memory layout in shared memory
|
||||||
auto layout_memory = makeSharedMemory(layout_region, sizeof(SharedDataLayout));
|
auto layout_memory = makeSharedMemory(layout_region, sizeof(SharedDataLayout), true);
|
||||||
auto shared_layout_ptr = new (layout_memory->Ptr()) SharedDataLayout();
|
auto shared_layout_ptr = new (layout_memory->Ptr()) SharedDataLayout();
|
||||||
auto absolute_file_index_path = boost::filesystem::absolute(config.file_index_path);
|
auto absolute_file_index_path = boost::filesystem::absolute(config.file_index_path);
|
||||||
|
|
||||||
@ -440,7 +424,7 @@ int Storage::Run()
|
|||||||
// allocate shared memory block
|
// allocate shared memory block
|
||||||
util::SimpleLogger().Write() << "allocating shared memory of "
|
util::SimpleLogger().Write() << "allocating shared memory of "
|
||||||
<< shared_layout_ptr->GetSizeOfLayout() << " bytes";
|
<< shared_layout_ptr->GetSizeOfLayout() << " bytes";
|
||||||
auto shared_memory = makeSharedMemory(data_region, shared_layout_ptr->GetSizeOfLayout());
|
auto shared_memory = makeSharedMemory(data_region, shared_layout_ptr->GetSizeOfLayout(), true);
|
||||||
char *shared_memory_ptr = static_cast<char *>(shared_memory->Ptr());
|
char *shared_memory_ptr = static_cast<char *>(shared_memory->Ptr());
|
||||||
|
|
||||||
// read actual data into shared memory object //
|
// read actual data into shared memory object //
|
||||||
@ -766,9 +750,8 @@ int Storage::Run()
|
|||||||
std::copy(entry_class_table.begin(), entry_class_table.end(), entry_class_ptr);
|
std::copy(entry_class_table.begin(), entry_class_table.end(), entry_class_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// acquire lock
|
|
||||||
auto data_type_memory =
|
auto data_type_memory =
|
||||||
makeSharedMemory(CURRENT_REGIONS, sizeof(SharedDataTimestamp), true, false, false);
|
makeSharedMemory(CURRENT_REGIONS, sizeof(SharedDataTimestamp), true);
|
||||||
SharedDataTimestamp *data_timestamp_ptr =
|
SharedDataTimestamp *data_timestamp_ptr =
|
||||||
static_cast<SharedDataTimestamp *>(data_type_memory->Ptr());
|
static_cast<SharedDataTimestamp *>(data_type_memory->Ptr());
|
||||||
|
|
||||||
@ -779,29 +762,6 @@ int Storage::Run()
|
|||||||
data_timestamp_ptr->layout = layout_region;
|
data_timestamp_ptr->layout = layout_region;
|
||||||
data_timestamp_ptr->data = data_region;
|
data_timestamp_ptr->data = data_region;
|
||||||
data_timestamp_ptr->timestamp += 1;
|
data_timestamp_ptr->timestamp += 1;
|
||||||
|
|
||||||
boost::interprocess::upgradable_lock<boost::interprocess::named_upgradable_mutex>
|
|
||||||
current_regions_upgradable_lock(std::move(current_regions_exclusive_lock));
|
|
||||||
|
|
||||||
util::SimpleLogger().Write(logDEBUG) << "waiting for server to switch dataset and request to finish";
|
|
||||||
if (!regions_1_available)
|
|
||||||
{
|
|
||||||
BOOST_ASSERT(regions_2_available);
|
|
||||||
boost::interprocess::scoped_lock<boost::interprocess::named_sharable_mutex>
|
|
||||||
regions_1_lock(barriers.regions_1_mutex);
|
|
||||||
util::SimpleLogger().Write(logDEBUG) << "switched. removing old regions 1";
|
|
||||||
deleteRegion(DATA_1);
|
|
||||||
deleteRegion(LAYOUT_1);
|
|
||||||
}
|
|
||||||
else if (!regions_2_available)
|
|
||||||
{
|
|
||||||
BOOST_ASSERT(regions_1_available);
|
|
||||||
boost::interprocess::scoped_lock<boost::interprocess::named_sharable_mutex>
|
|
||||||
regions_2_lock(barriers.regions_2_mutex);
|
|
||||||
util::SimpleLogger().Write(logDEBUG) << "switched. removing regions 2";
|
|
||||||
deleteRegion(DATA_2);
|
|
||||||
deleteRegion(LAYOUT_2);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
util::SimpleLogger().Write() << "all data loaded";
|
util::SimpleLogger().Write() << "all data loaded";
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user