in cppcache/src/LocalRegion.cpp [2355:2469]
GfErrType LocalRegion::destroyRegionNoThrow(
const std::shared_ptr<Serializable>& aCallbackArgument,
bool removeFromParent, const CacheEventFlags eventFlags) {
// Get global locks to synchronize with failover thread.
// TODO: This should go into RegionGlobalLocks
// The distMngrsLock is required before RegionGlobalLocks since failover
// thread acquires distMngrsLock and then tries to acquire endpoints lock
// which is already taken by RegionGlobalLocks here.
DistManagersLockGuard _guard(m_cacheImpl->tcrConnectionManager());
RegionGlobalLocks acquireLocks(this);
// Fix for BUG:849, i.e Remove subscription on region before destroying the
// region
if (eventFlags == CacheEventFlags::LOCAL) {
if (unregisterKeysBeforeDestroyRegion() != GF_NOERR) {
LOGDEBUG(
"DEBUG :: LocalRegion::destroyRegionNoThrow UnregisteredKeys "
"Failed");
}
}
boost::unique_lock<decltype(mutex_)> guard{mutex_};
if (m_destroyPending) {
if (eventFlags.isCacheClose()) {
return GF_NOERR;
} else {
return GF_CACHE_REGION_DESTROYED_EXCEPTION;
}
}
m_destroyPending = true;
LOGDEBUG("LocalRegion::destroyRegionNoThrow( ): set flag destroy-pending.");
GfErrType err = GF_NOERR;
// do not invoke the writer for expiry or notification
if (!eventFlags.isNotification() && !eventFlags.isEvictOrExpire()) {
if (!invokeCacheWriterForRegionEvent(aCallbackArgument, eventFlags,
BEFORE_REGION_DESTROY)) {
// do not let CacheWriter veto when this is Cache::close()
if (!eventFlags.isCacheClose()) {
LOGFINE("Cache writer prevented region destroy");
m_destroyPending = false;
return GF_CACHEWRITER_ERROR;
}
}
// for the expiry case try the local destroy first and remote
// destroy only if local destroy succeeds
if (!eventFlags.isLocal()) {
err = destroyRegionNoThrow_remote(aCallbackArgument);
if (err != GF_NOERR) {
m_destroyPending = false;
return err;
}
}
}
LOGFINE("Region %s is being destroyed", m_fullPath.c_str());
{
auto&& lock = m_subRegions.make_lock();
for (const auto& kv : m_subRegions) {
// TODO: remove unnecessary dynamic_cast by having m_subRegions hold
// RegionInternal and invoke the destroy method in that
if (auto subRegion =
std::dynamic_pointer_cast<RegionInternal>(kv.second)) {
// for subregions never remove from parent since that will cause
// the region to be destroyed and SEGV; unbind_all takes care of that
// Also don't send remote destroy message for sub-regions
err = subRegion->destroyRegionNoThrow(
aCallbackArgument, false, eventFlags | CacheEventFlags::LOCAL);
// for Cache::close() keep going as far as possible
if (err != GF_NOERR && !eventFlags.isCacheClose()) {
m_destroyPending = false;
return err;
}
}
}
}
m_subRegions.clear();
// for the expiry case try the local destroy first and remote
// destroy only if local destroy succeeds
if (eventFlags.isEvictOrExpire() && !eventFlags.isLocal()) {
err = destroyRegionNoThrow_remote(aCallbackArgument);
if (err != GF_NOERR) {
m_destroyPending = false;
return err;
}
}
// if we are not removing from parent then this is a proper
// region close so invoke listener->close() also
err = invokeCacheListenerForRegionEvent(aCallbackArgument, eventFlags,
AFTER_REGION_DESTROY);
release(true);
if (m_regionAttributes.getCachingEnabled()) {
_GEODE_SAFE_DELETE(m_entries);
}
if (removeFromParent) {
if (m_parentRegion == nullptr) {
m_cacheImpl->removeRegion(m_name.c_str());
} else {
LocalRegion* parent = dynamic_cast<LocalRegion*>(m_parentRegion.get());
if (parent != nullptr) {
parent->removeRegion(m_name);
if (!eventFlags.isEvictOrExpire()) {
parent->updateAccessAndModifiedTime(true);
}
}
}
}
return err;
}