Fix a potential deadlock when opening a realm

This commit is contained in:
Thomas Goyne 2015-08-20 12:27:23 -07:00
parent e87a507223
commit c3a9489b02
2 changed files with 15 additions and 9 deletions

View File

@ -24,6 +24,11 @@
using namespace realm; using namespace realm;
using namespace realm::_impl; using namespace realm::_impl;
struct realm::_impl::CachedRealm {
std::weak_ptr<Realm> realm;
std::thread::id thread_id;
};
static std::mutex s_coordinator_mutex; static std::mutex s_coordinator_mutex;
static std::map<std::string, std::weak_ptr<RealmCoordinator>> s_coordinators_per_path; static std::map<std::string, std::weak_ptr<RealmCoordinator>> s_coordinators_per_path;
@ -86,11 +91,11 @@ std::shared_ptr<Realm> RealmCoordinator::get_realm(Realm::Config config)
auto thread_id = std::this_thread::get_id(); auto thread_id = std::this_thread::get_id();
if (config.cache) { if (config.cache) {
for (auto& weakRealm : m_cached_realms) { for (auto& cachedRealm : m_cached_realms) {
// can be null if we jumped in between ref count hitting zero and if (cachedRealm.thread_id == thread_id) {
// unregister_realm() getting the lock // can be null if we jumped in between ref count hitting zero and
if (auto realm = weakRealm.lock()) { // unregister_realm() getting the lock
if (realm->thread_id() == thread_id) { if (auto realm = cachedRealm.realm.lock()) {
return realm; return realm;
} }
} }
@ -103,7 +108,7 @@ std::shared_ptr<Realm> RealmCoordinator::get_realm(Realm::Config config)
m_notifier->add_realm(realm.get()); m_notifier->add_realm(realm.get());
} }
if (config.cache) { if (config.cache) {
m_cached_realms.push_back(realm); m_cached_realms.push_back({realm, thread_id});
} }
return realm; return realm;
} }
@ -135,7 +140,7 @@ void RealmCoordinator::unregister_realm(Realm* realm)
m_notifier->remove_realm(realm); m_notifier->remove_realm(realm);
} }
for (size_t i = 0; i < m_cached_realms.size(); ++i) { for (size_t i = 0; i < m_cached_realms.size(); ++i) {
if (m_cached_realms[i].expired()) { if (m_cached_realms[i].realm.expired()) {
if (i + 1 < m_cached_realms.size()) { if (i + 1 < m_cached_realms.size()) {
m_cached_realms[i] = std::move(m_cached_realms.back()); m_cached_realms[i] = std::move(m_cached_realms.back());
} }
@ -159,7 +164,7 @@ void RealmCoordinator::clear_cache()
} }
for (auto& cached_realm : coordinator->m_cached_realms) { for (auto& cached_realm : coordinator->m_cached_realms) {
if (auto realm = cached_realm.lock()) { if (auto realm = cached_realm.realm.lock()) {
realms_to_close.push_back(realm); realms_to_close.push_back(realm);
} }
} }

View File

@ -26,6 +26,7 @@
namespace realm { namespace realm {
namespace _impl { namespace _impl {
class ExternalCommitHelper; class ExternalCommitHelper;
struct CachedRealm;
// RealmCoordinator manages the weak cache of Realm instances and communication // RealmCoordinator manages the weak cache of Realm instances and communication
// between per-thread Realm instances for a given file // between per-thread Realm instances for a given file
@ -66,7 +67,7 @@ private:
Realm::Config m_config; Realm::Config m_config;
std::mutex m_realm_mutex; std::mutex m_realm_mutex;
std::vector<std::weak_ptr<Realm>> m_cached_realms; std::vector<CachedRealm> m_cached_realms;
std::unique_ptr<_impl::ExternalCommitHelper> m_notifier; std::unique_ptr<_impl::ExternalCommitHelper> m_notifier;
}; };