Fix assertion failure when a notifier is removed before it runs

This commit is contained in:
Thomas Goyne 2016-04-25 10:15:56 -07:00
parent eee6e55eb0
commit 8879212111
1 changed files with 20 additions and 6 deletions

View File

@ -235,13 +235,17 @@ void RealmCoordinator::pin_version(uint_fast64_t version, uint_fast32_t index)
}
else if (m_new_notifiers.empty()) {
// If this is the first notifier then we don't already have a read transaction
REALM_ASSERT_3(m_advancer_sg->get_transact_stage(), ==, SharedGroup::transact_Ready);
m_advancer_sg->begin_read(versionid);
}
else if (versionid < m_advancer_sg->get_version_of_current_transaction()) {
// Ensure we're holding a readlock on the oldest version we have a
// handover object for, as handover objects don't
m_advancer_sg->end_read();
m_advancer_sg->begin_read(versionid);
else {
REALM_ASSERT_3(m_advancer_sg->get_transact_stage(), ==, SharedGroup::transact_Reading);
if (versionid < m_advancer_sg->get_version_of_current_transaction()) {
// Ensure we're holding a readlock on the oldest version we have a
// handover object for, as handover objects don't
m_advancer_sg->end_read();
m_advancer_sg->begin_read(versionid);
}
}
}
@ -282,10 +286,12 @@ void RealmCoordinator::clean_up_dead_notifiers()
// are no notifiers left, but don't close them entirely as opening shared
// groups is expensive
if (m_notifiers.empty() && m_notifier_sg) {
REALM_ASSERT_3(m_notifier_sg->get_transact_stage(), ==, SharedGroup::transact_Reading);
m_notifier_sg->end_read();
}
}
if (swap_remove(m_new_notifiers)) {
REALM_ASSERT_3(m_advancer_sg->get_transact_stage(), ==, SharedGroup::transact_Reading);
if (m_new_notifiers.empty() && m_advancer_sg) {
m_advancer_sg->end_read();
}
@ -424,7 +430,14 @@ void RealmCoordinator::run_async_notifiers()
IncrementalChangeInfo new_notifier_change_info(*m_advancer_sg, new_notifiers);
if (!new_notifiers.empty()) {
REALM_ASSERT(m_advancer_sg->get_version_of_current_transaction() == new_notifiers.front()->version());
REALM_ASSERT_3(m_advancer_sg->get_transact_stage(), ==, SharedGroup::transact_Reading);
REALM_ASSERT_3(m_advancer_sg->get_version_of_current_transaction().version,
<=, new_notifiers.front()->version().version);
// The advancer SG can be at an older version than the oldest new notifier
// if a notifier was added and then removed before it ever got the chance
// to run, as we don't move the pin forward when removing dead notifiers
transaction::advance(*m_advancer_sg, nullptr, new_notifiers.front()->version());
// Advance each of the new notifiers to the latest version, attaching them
// to the SG at their handover version. This requires a unique
@ -446,6 +459,7 @@ void RealmCoordinator::run_async_notifiers()
version = m_advancer_sg->get_version_of_current_transaction();
m_advancer_sg->end_read();
}
REALM_ASSERT_3(m_advancer_sg->get_transact_stage(), ==, SharedGroup::transact_Ready);
// Make a copy of the notifiers vector and then release the lock to avoid
// blocking other threads trying to register or unregister notifiers while we run them