Only keep reader lock on shared memory during queries.
This commit is contained in:
committed by
Patrick Niklaus
parent
c69545c47a
commit
847f530c8e
@@ -5,10 +5,11 @@
|
||||
|
||||
#include "storage/shared_datatype.hpp"
|
||||
#include "storage/shared_memory.hpp"
|
||||
#include "storage/shared_barriers.hpp"
|
||||
|
||||
#include <boost/interprocess/sync/named_upgradable_mutex.hpp>
|
||||
#include <boost/thread/locks.hpp>
|
||||
#include <boost/thread/lock_types.hpp>
|
||||
#include <boost/thread/locks.hpp>
|
||||
#include <boost/thread/shared_mutex.hpp>
|
||||
|
||||
#include <memory>
|
||||
@@ -31,7 +32,7 @@ class DataWatchdog
|
||||
public:
|
||||
DataWatchdog()
|
||||
: 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}
|
||||
{
|
||||
}
|
||||
@@ -42,26 +43,13 @@ class DataWatchdog
|
||||
return storage::SharedMemory::RegionExists(storage::CURRENT_REGIONS);
|
||||
}
|
||||
|
||||
// Check if it might be worth to try to aquire a exclusive lock
|
||||
bool HasNewRegion() const
|
||||
{
|
||||
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;
|
||||
}
|
||||
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
|
||||
void MaybeLoadNewRegion(std::shared_ptr<datafacade::BaseDataFacade> &facade)
|
||||
LockAndFacade GetDataFacade()
|
||||
{
|
||||
const boost::interprocess::sharable_lock<boost::interprocess::named_upgradable_mutex> lock(
|
||||
shared_barriers->current_regions_mutex);
|
||||
@@ -69,31 +57,55 @@ class DataWatchdog
|
||||
const auto shared_timestamp =
|
||||
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);
|
||||
|
||||
// if more then one request tried to aquire the write lock
|
||||
// we might get overtaken before we actually do the writing
|
||||
// in that case we don't modify anthing
|
||||
if (shared_timestamp->timestamp == current_timestamp.timestamp)
|
||||
{
|
||||
BOOST_ASSERT(shared_timestamp->layout == current_timestamp.layout);
|
||||
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;
|
||||
// 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);
|
||||
return get_locked_facade();
|
||||
}
|
||||
|
||||
// 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:
|
||||
@@ -105,6 +117,7 @@ class DataWatchdog
|
||||
std::unique_ptr<storage::SharedMemory> shared_regions;
|
||||
|
||||
mutable boost::shared_mutex facade_mutex;
|
||||
std::shared_ptr<datafacade::SharedDataFacade> facade;
|
||||
storage::SharedDataTimestamp current_timestamp;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
// implements all data storage when shared memory _IS_ used
|
||||
|
||||
#include "storage/shared_barriers.hpp"
|
||||
#include "storage/shared_datatype.hpp"
|
||||
#include "storage/shared_memory.hpp"
|
||||
#include "engine/datafacade/datafacade_base.hpp"
|
||||
@@ -66,11 +65,9 @@ class SharedDataFacade final : public BaseDataFacade
|
||||
storage::SharedDataLayout *data_layout;
|
||||
char *shared_memory;
|
||||
|
||||
std::shared_ptr<storage::SharedBarriers> shared_barriers;
|
||||
storage::SharedDataType layout_region;
|
||||
storage::SharedDataType data_region;
|
||||
unsigned shared_timestamp;
|
||||
boost::interprocess::sharable_lock<boost::interprocess::named_sharable_mutex> regions_lock;
|
||||
|
||||
unsigned m_check_sum;
|
||||
std::unique_ptr<QueryGraph> m_query_graph;
|
||||
@@ -384,26 +381,22 @@ class SharedDataFacade final : public BaseDataFacade
|
||||
public:
|
||||
virtual ~SharedDataFacade() {}
|
||||
|
||||
SharedDataFacade(const std::shared_ptr<storage::SharedBarriers> &shared_barriers_,
|
||||
storage::SharedDataType layout_region_,
|
||||
SharedDataFacade(storage::SharedDataType layout_region_,
|
||||
storage::SharedDataType data_region_,
|
||||
unsigned shared_timestamp_)
|
||||
: shared_barriers(shared_barriers_),
|
||||
layout_region(layout_region_), data_region(data_region_),
|
||||
shared_timestamp(shared_timestamp_),
|
||||
regions_lock(layout_region == storage::LAYOUT_1 ? shared_barriers->regions_1_mutex
|
||||
: shared_barriers->regions_2_mutex)
|
||||
: layout_region(layout_region_), data_region(data_region_),
|
||||
shared_timestamp(shared_timestamp_)
|
||||
{
|
||||
util::SimpleLogger().Write(logDEBUG) << "Loading new data with shared timestamp "
|
||||
<< shared_timestamp;
|
||||
|
||||
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());
|
||||
|
||||
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());
|
||||
|
||||
LoadGraph();
|
||||
|
||||
@@ -85,8 +85,9 @@ class Engine final
|
||||
std::unique_ptr<plugins::MatchPlugin> match_plugin;
|
||||
std::unique_ptr<plugins::TilePlugin> tile_plugin;
|
||||
|
||||
// reading and setting this is protected by locking in the watchdog
|
||||
mutable std::shared_ptr<datafacade::BaseDataFacade> query_data_facade;
|
||||
// note in case of shared memory this will be empty, since the watchdog
|
||||
// will provide us with the up-to-date facade
|
||||
std::shared_ptr<datafacade::BaseDataFacade> immutable_data_facade;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user