Change to condvar signaling if data region swapped

This commit is contained in:
Michael Krasnyk
2016-12-26 01:00:37 +01:00
committed by Patrick Niklaus
parent 774b8688ca
commit fce8d72895
10 changed files with 143 additions and 362 deletions
+43 -93
View File
@@ -13,6 +13,7 @@
#include <boost/thread/shared_mutex.hpp>
#include <memory>
#include <thread>
namespace osrm
{
@@ -26,10 +27,17 @@ class DataWatchdog
{
public:
DataWatchdog()
: shared_barriers{std::make_shared<storage::SharedBarriers>()},
shared_regions(storage::makeSharedMemory(storage::CURRENT_REGION)),
current_timestamp{storage::REGION_NONE, 0}
: active(true)
, timestamp(0)
{
watcher = std::thread(&DataWatchdog::Run, this);
}
~DataWatchdog()
{
active = false;
barrier.region_condition.notify_all();
watcher.join();
}
// Tries to connect to the shared memory containing the regions table
@@ -38,102 +46,44 @@ class DataWatchdog
return storage::SharedMemory::RegionExists(storage::CURRENT_REGION);
}
using RegionsLock =
boost::interprocess::sharable_lock<boost::interprocess::named_sharable_mutex>;
using LockAndFacade = std::pair<RegionsLock, std::shared_ptr<datafacade::BaseDataFacade>>;
// This will either update the contens of facade or just leave it as is
// if the update was already done by another thread
LockAndFacade GetDataFacade()
auto GetDataFacade() const
{
const boost::interprocess::sharable_lock<boost::interprocess::named_upgradable_mutex> lock(
shared_barriers->current_region_mutex);
const auto shared_timestamp =
static_cast<const storage::SharedDataTimestamp *>(shared_regions->Ptr());
const auto get_locked_facade = [this, shared_timestamp](
const std::shared_ptr<datafacade::SharedMemoryDataFacade> &facade) {
if (current_timestamp.region == storage::REGION_1)
{
return std::make_pair(RegionsLock(shared_barriers->region_1_mutex), facade);
}
else
{
BOOST_ASSERT(current_timestamp.region == storage::REGION_2);
return std::make_pair(RegionsLock(shared_barriers->region_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)
{
if (auto facade = cached_facade.lock())
{
BOOST_ASSERT(shared_timestamp->region == current_timestamp.region);
return get_locked_facade(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);
// we might get overtaken before we actually do the writing
// in that case we don't modify anything
if (shared_timestamp->timestamp == current_timestamp.timestamp)
{
if (auto facade = cached_facade.lock())
{
BOOST_ASSERT(shared_timestamp->region == current_timestamp.region);
return get_locked_facade(facade);
}
}
// this thread has won and can update the data
boost::upgrade_to_unique_lock<boost::upgrade_mutex> unique_facade_lock(facade_lock);
// if two threads try to enter this critical section one will loose
// and will find an up-to-date instance of the shared data facade
if (shared_timestamp->timestamp == current_timestamp.timestamp)
{
// if the thread that updated the facade finishes the query before
// we can aquire our handle here, we need to regenerate
if (auto facade = cached_facade.lock())
{
BOOST_ASSERT(shared_timestamp->region == current_timestamp.region);
return get_locked_facade(facade);
}
}
else
{
current_timestamp = *shared_timestamp;
}
auto new_facade = std::make_shared<datafacade::SharedMemoryDataFacade>(
shared_barriers, current_timestamp.region, current_timestamp.timestamp);
cached_facade = new_facade;
return get_locked_facade(new_facade);
return facade;
}
private:
// mutexes should be mutable even on const objects: This enables
// marking functions as logical const and thread-safe.
std::shared_ptr<storage::SharedBarriers> shared_barriers;
// shared memory table containing pointers to all shared regions
std::unique_ptr<storage::SharedMemory> shared_regions;
void Run()
{
boost::interprocess::scoped_lock<boost::interprocess::named_mutex>
current_region_lock(barrier.region_mutex);
mutable boost::shared_mutex facade_mutex;
std::weak_ptr<datafacade::SharedMemoryDataFacade> cached_facade;
storage::SharedDataTimestamp current_timestamp;
auto shared_memory = makeSharedMemory(storage::CURRENT_REGION);
auto current = static_cast<storage::SharedDataTimestamp *>(shared_memory->Ptr());
while (active)
{
if (timestamp != current->timestamp)
{
util::Log() << "updating facade to region " << storage::regionToString(current->region)
<< " with timestamp " << current->timestamp;
facade = std::make_shared<datafacade::SharedMemoryDataFacade>(current->region);
timestamp = current->timestamp;
}
barrier.region_condition.wait(current_region_lock);
}
facade.reset();
util::Log() << "DataWatchdog thread stopped";
}
storage::SharedBarriers barrier;
std::thread watcher;
bool active;
unsigned timestamp;
std::shared_ptr<datafacade::SharedMemoryDataFacade> facade;
};
}
}
@@ -25,57 +25,16 @@ class SharedMemoryDataFacade : public ContiguousInternalMemoryDataFacadeBase
protected:
std::unique_ptr<storage::SharedMemory> m_large_memory;
std::shared_ptr<storage::SharedBarriers> shared_barriers;
storage::SharedDataType data_region;
unsigned shared_timestamp;
SharedMemoryDataFacade() {}
public:
// this function handle the deallocation of the shared memory it we can prove it will not be
// used anymore. We crash hard here if something goes wrong (noexcept).
virtual ~SharedMemoryDataFacade() noexcept
SharedMemoryDataFacade(storage::SharedDataType data_region)
: data_region(data_region)
{
// Now check if this is still the newest dataset
boost::interprocess::sharable_lock<boost::interprocess::named_upgradable_mutex>
current_regions_lock(shared_barriers->current_region_mutex,
boost::interprocess::defer_lock);
boost::interprocess::scoped_lock<boost::interprocess::named_sharable_mutex> exclusive_lock(
data_region == storage::REGION_1 ? shared_barriers->region_1_mutex
: shared_barriers->region_2_mutex,
boost::interprocess::defer_lock);
// if this returns false this is still in use
if (current_regions_lock.try_lock() && exclusive_lock.try_lock())
{
if (storage::SharedMemory::RegionExists(data_region))
{
auto shared_region = storage::makeSharedMemory(storage::CURRENT_REGION);
const auto current_timestamp =
static_cast<const storage::SharedDataTimestamp *>(shared_region->Ptr());
// check if the memory region referenced by this facade needs cleanup
if (current_timestamp->region == data_region)
{
util::Log(logDEBUG) << "Retaining data with shared timestamp "
<< shared_timestamp;
}
else
{
storage::SharedMemory::Remove(data_region);
}
}
}
}
SharedMemoryDataFacade(const std::shared_ptr<storage::SharedBarriers> &shared_barriers_,
storage::SharedDataType data_region_,
unsigned shared_timestamp_)
: shared_barriers(shared_barriers_), data_region(data_region_),
shared_timestamp(shared_timestamp_)
{
util::Log(logDEBUG) << "Loading new data with shared timestamp " << shared_timestamp;
util::Log(logDEBUG) << "Loading new data for region " << regionToString(data_region);
BOOST_ASSERT(storage::SharedMemory::RegionExists(data_region));
m_large_memory = storage::makeSharedMemory(data_region);
+1 -1
View File
@@ -50,7 +50,7 @@ class Engine final
Status Tile(const api::TileParameters &parameters, std::string &result) const;
private:
std::unique_ptr<storage::SharedBarriers> lock;
//std::unique_ptr<storage::SharedBarriers> lock;
std::unique_ptr<DataWatchdog> watchdog;
const plugins::ViaRoutePlugin route_plugin;
+9 -12
View File
@@ -1,8 +1,8 @@
#ifndef SHARED_BARRIERS_HPP
#define SHARED_BARRIERS_HPP
#include <boost/interprocess/sync/named_sharable_mutex.hpp>
#include <boost/interprocess/sync/named_upgradable_mutex.hpp>
#include <boost/interprocess/sync/named_condition.hpp>
#include <boost/interprocess/sync/named_mutex.hpp>
namespace osrm
{
@@ -13,22 +13,19 @@ struct SharedBarriers
{
SharedBarriers()
: current_region_mutex(boost::interprocess::open_or_create, "current_region"),
region_1_mutex(boost::interprocess::open_or_create, "region_1"),
region_2_mutex(boost::interprocess::open_or_create, "region_2")
: region_mutex(boost::interprocess::open_or_create, "osrm-region")
, region_condition(boost::interprocess::open_or_create, "osrm-region-cv")
{
}
static void resetCurrentRegion()
static void remove()
{
boost::interprocess::named_sharable_mutex::remove("current_region");
boost::interprocess::named_mutex::remove("osrm-region");
boost::interprocess::named_condition::remove("osrm-region-cv");
}
static void resetRegion1() { boost::interprocess::named_sharable_mutex::remove("region_1"); }
static void resetRegion2() { boost::interprocess::named_sharable_mutex::remove("region_2"); }
boost::interprocess::named_upgradable_mutex current_region_mutex;
boost::interprocess::named_sharable_mutex region_1_mutex;
boost::interprocess::named_sharable_mutex region_2_mutex;
boost::interprocess::named_mutex region_mutex;
boost::interprocess::named_condition region_condition;
};
}
}
+4 -7
View File
@@ -19,7 +19,6 @@
#include <sys/shm.h>
#endif
// #include <cstring>
#include <cstdint>
#include <algorithm>
@@ -150,25 +149,23 @@ class SharedMemory
SharedMemory(const boost::filesystem::path &lock_file,
const int id,
const uint64_t size = 0,
bool read_write = false)
const uint64_t size = 0)
{
sprintf(key, "%s.%d", "osrm.lock", id);
auto access = read_write ? boost::interprocess::read_write : boost::interprocess::read_only;
if (0 == size)
{ // read_only
shm = boost::interprocess::shared_memory_object(
boost::interprocess::open_only,
key,
read_write ? boost::interprocess::read_write : boost::interprocess::read_only);
region = boost::interprocess::mapped_region(shm, access);
boost::interprocess::read_only);
region = boost::interprocess::mapped_region(shm, boost::interprocess::read_only);
}
else
{ // writeable pointer
shm = boost::interprocess::shared_memory_object(
boost::interprocess::open_or_create, key, boost::interprocess::read_write);
shm.truncate(size);
region = boost::interprocess::mapped_region(shm, access);
region = boost::interprocess::mapped_region(shm, boost::interprocess::read_write);
util::Log(logDEBUG) << "writeable memory allocated " << size << " bytes";
}
+3 -8
View File
@@ -31,6 +31,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "storage/shared_datatype.hpp"
#include "storage/storage_config.hpp"
#include <boost/interprocess/sync/named_mutex.hpp>
#include <boost/filesystem/path.hpp>
#include <string>
@@ -44,20 +45,14 @@ class Storage
public:
Storage(StorageConfig config);
enum ReturnCode
{
Ok,
Error,
Retry
};
ReturnCode Run(int max_wait);
int Run();
void PopulateLayout(DataLayout &layout);
void PopulateData(const DataLayout &layout, char *memory_ptr);
private:
StorageConfig config;
boost::interprocess::named_mutex datastore_mutex;
};
}
}