mirror of https://gitee.com/bigwinds/arangodb
Merge pull request #4922 from arangodb/bug-fix/internal-issue-#348.1
issue 348.1: use a view validity lock instead of a view member lock for snapshot readers
This commit is contained in:
commit
614cf73ff8
|
@ -97,7 +97,7 @@ typedef irs::async_utils::read_write_mutex::write_mutex WriteMutex;
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
class CompoundReader final: public arangodb::iresearch::PrimaryKeyIndexReader {
|
class CompoundReader final: public arangodb::iresearch::PrimaryKeyIndexReader {
|
||||||
public:
|
public:
|
||||||
CompoundReader(irs::async_utils::read_write_mutex& mutex);
|
CompoundReader(ReadMutex& viewMutex);
|
||||||
irs::sub_reader const& operator[](
|
irs::sub_reader const& operator[](
|
||||||
size_t subReaderId
|
size_t subReaderId
|
||||||
) const noexcept override {
|
) const noexcept override {
|
||||||
|
@ -147,15 +147,12 @@ class CompoundReader final: public arangodb::iresearch::PrimaryKeyIndexReader {
|
||||||
SubReadersType::const_iterator _itr;
|
SubReadersType::const_iterator _itr;
|
||||||
};
|
};
|
||||||
|
|
||||||
// order is important
|
|
||||||
ReadMutex _mutex;
|
|
||||||
std::unique_lock<ReadMutex> _lock;
|
|
||||||
std::vector<irs::directory_reader> _readers;
|
std::vector<irs::directory_reader> _readers;
|
||||||
SubReadersType _subReaders;
|
SubReadersType _subReaders;
|
||||||
|
std::lock_guard<ReadMutex> _viewLock; // prevent data-store deallocation (lock @ AsyncSelf)
|
||||||
};
|
};
|
||||||
|
|
||||||
CompoundReader::CompoundReader(irs::async_utils::read_write_mutex& mutex)
|
CompoundReader::CompoundReader(ReadMutex& viewMutex): _viewLock(viewMutex) {
|
||||||
: _mutex(mutex), _lock(_mutex) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompoundReader::add(irs::directory_reader const& reader) {
|
void CompoundReader::add(irs::directory_reader const& reader) {
|
||||||
|
@ -219,7 +216,7 @@ uint64_t CompoundReader::live_docs_count() const {
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
struct ViewState: public arangodb::TransactionState::Cookie {
|
struct ViewState: public arangodb::TransactionState::Cookie {
|
||||||
CompoundReader _snapshot;
|
CompoundReader _snapshot;
|
||||||
ViewState(irs::async_utils::read_write_mutex& mutex): _snapshot(mutex) {}
|
ViewState(ReadMutex& mutex): _snapshot(mutex) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -287,7 +284,7 @@ size_t directoryMemory(irs::directory const& directory, TRI_voc_cid_t viewId) no
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
arangodb::iresearch::IResearchLink* findFirstMatchingLink(
|
std::shared_ptr<arangodb::iresearch::IResearchLink> findFirstMatchingLink(
|
||||||
arangodb::LogicalCollection const& collection,
|
arangodb::LogicalCollection const& collection,
|
||||||
arangodb::iresearch::IResearchView const& view
|
arangodb::iresearch::IResearchView const& view
|
||||||
) {
|
) {
|
||||||
|
@ -298,7 +295,8 @@ arangodb::iresearch::IResearchLink* findFirstMatchingLink(
|
||||||
|
|
||||||
// TODO FIXME find a better way to retrieve an iResearch Link
|
// TODO FIXME find a better way to retrieve an iResearch Link
|
||||||
// cannot use static_cast/reinterpret_cast since Index is not related to IResearchLink
|
// cannot use static_cast/reinterpret_cast since Index is not related to IResearchLink
|
||||||
auto* link = dynamic_cast<arangodb::iresearch::IResearchLink*>(index.get());
|
auto link =
|
||||||
|
std::dynamic_pointer_cast<arangodb::iresearch::IResearchLink>(index);
|
||||||
|
|
||||||
if (link && *link == view) {
|
if (link && *link == view) {
|
||||||
return link; // found required link
|
return link; // found required link
|
||||||
|
@ -470,7 +468,7 @@ arangodb::Result updateLinks(
|
||||||
struct State {
|
struct State {
|
||||||
std::shared_ptr<arangodb::LogicalCollection> _collection;
|
std::shared_ptr<arangodb::LogicalCollection> _collection;
|
||||||
size_t _collectionsToLockOffset; // std::numeric_limits<size_t>::max() == removal only
|
size_t _collectionsToLockOffset; // std::numeric_limits<size_t>::max() == removal only
|
||||||
arangodb::iresearch::IResearchLink const* _link = nullptr;
|
std::shared_ptr<arangodb::iresearch::IResearchLink> _link;
|
||||||
size_t _linkDefinitionsOffset;
|
size_t _linkDefinitionsOffset;
|
||||||
bool _valid = true;
|
bool _valid = true;
|
||||||
explicit State(size_t collectionsToLockOffset)
|
explicit State(size_t collectionsToLockOffset)
|
||||||
|
@ -852,17 +850,6 @@ IResearchView::IResearchView(
|
||||||
|
|
||||||
// initialize transaction write callback
|
// initialize transaction write callback
|
||||||
_trxWriteCallback = [viewPtr](arangodb::TransactionState& state)->void {
|
_trxWriteCallback = [viewPtr](arangodb::TransactionState& state)->void {
|
||||||
/* FIXME TODO recursive read locks may deadlock if a FlushThread tries to
|
|
||||||
* aquire a write-lock in the middle of a two read locks
|
|
||||||
* this may occur if a snapshot() is held by the current thread
|
|
||||||
* in any transaction
|
|
||||||
*/
|
|
||||||
if (state.cookie(viewPtr)) {
|
|
||||||
LOG_TOPIC(WARN, iresearch::IResearchFeature::IRESEARCH)
|
|
||||||
<< "executing collection write operations is not supported with a lock on view '" << viewPtr->name() << "'";
|
|
||||||
state.cookie(viewPtr, nullptr); // a temporary workaround for JavaScript tests that lock the view then write to collections
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (state.status()) {
|
switch (state.status()) {
|
||||||
case transaction::Status::ABORTED: {
|
case transaction::Status::ABORTED: {
|
||||||
auto res = viewPtr->finish(state.id(), false);
|
auto res = viewPtr->finish(state.id(), false);
|
||||||
|
@ -1001,7 +988,7 @@ IResearchView::~IResearchView() {
|
||||||
{
|
{
|
||||||
WriteMutex mutex(_asyncSelf->_mutex);
|
WriteMutex mutex(_asyncSelf->_mutex);
|
||||||
SCOPED_LOCK(mutex); // wait for all the view users to finish
|
SCOPED_LOCK(mutex); // wait for all the view users to finish
|
||||||
_asyncSelf->_value.store(nullptr); // the view is being deallocated, its use is not longer valid
|
_asyncSelf->_value.store(nullptr); // the view is being deallocated, its use is no longer valid
|
||||||
}
|
}
|
||||||
|
|
||||||
_asyncTerminate.store(true); // mark long-running async jobs for terminatation
|
_asyncTerminate.store(true); // mark long-running async jobs for terminatation
|
||||||
|
@ -1063,6 +1050,12 @@ void IResearchView::drop() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
WriteMutex mutex(_asyncSelf->_mutex);
|
||||||
|
SCOPED_LOCK(mutex); // wait for all the view users to finish
|
||||||
|
_asyncSelf->_value.store(nullptr); // the view data-stores are being deallocated, view use is no longer valid
|
||||||
|
}
|
||||||
|
|
||||||
_asyncTerminate.store(true); // mark long-running async jobs for terminatation
|
_asyncTerminate.store(true); // mark long-running async jobs for terminatation
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -1092,11 +1085,14 @@ void IResearchView::drop() {
|
||||||
try {
|
try {
|
||||||
_storeByTid.clear();
|
_storeByTid.clear();
|
||||||
|
|
||||||
auto& memoryStore = activeMemoryStore();
|
for (size_t i = 0, count = IRESEARCH_COUNTOF(_memoryNodes); i < count; ++i) {
|
||||||
|
auto& memoryStore = _memoryNodes[i]._store;
|
||||||
|
|
||||||
memoryStore._writer->close();
|
memoryStore._writer->close();
|
||||||
memoryStore._writer.reset();
|
memoryStore._writer.reset();
|
||||||
memoryStore._directory->close();
|
memoryStore._directory->close();
|
||||||
memoryStore._directory.reset();
|
memoryStore._directory.reset();
|
||||||
|
}
|
||||||
|
|
||||||
if (_storePersisted) {
|
if (_storePersisted) {
|
||||||
_storePersisted._writer->close();
|
_storePersisted._writer->close();
|
||||||
|
@ -1824,10 +1820,17 @@ PrimaryKeyIndexReader* IResearchView::snapshot(
|
||||||
<< "failed to sync while creating snapshot for IResearch view '" << name() << "', previous snapshot will be used instead";
|
<< "failed to sync while creating snapshot for IResearch view '" << name() << "', previous snapshot will be used instead";
|
||||||
}
|
}
|
||||||
|
|
||||||
auto cookiePtr = irs::memory::make_unique<ViewState>(_mutex); // will aquire read-lock since members can be asynchronously updated
|
auto cookiePtr = irs::memory::make_unique<ViewState>(_asyncSelf->mutex()); // will aquire read-lock to prevent data-store deallocation
|
||||||
auto& reader = cookiePtr->_snapshot;
|
auto& reader = cookiePtr->_snapshot;
|
||||||
|
|
||||||
|
if (!_asyncSelf->get()) {
|
||||||
|
return nullptr; // the current view is no longer valid (checked after ReadLock aquisition)
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
ReadMutex mutex(_mutex); // _memoryNodes/_storePersisted can be asynchronously updated
|
||||||
|
SCOPED_LOCK(mutex);
|
||||||
|
|
||||||
reader.add(_memoryNode->_store._reader);
|
reader.add(_memoryNode->_store._reader);
|
||||||
SCOPED_LOCK(_toFlush->_readMutex);
|
SCOPED_LOCK(_toFlush->_readMutex);
|
||||||
reader.add(_toFlush->_store._reader);
|
reader.add(_toFlush->_store._reader);
|
||||||
|
|
Loading…
Reference in New Issue