in cppcache/src/LocalRegion.cpp [1636:1779]
GfErrType LocalRegion::updateNoThrow(
const std::shared_ptr<CacheableKey>& key,
const std::shared_ptr<Cacheable>& value,
const std::shared_ptr<Serializable>& aCallbackArgument,
std::shared_ptr<Cacheable>& oldValue, int updateCount,
const CacheEventFlags eventFlags, std::shared_ptr<VersionTag> versionTag,
DataInput* delta, std::shared_ptr<EventId> eventId) {
GfErrType err = GF_NOERR;
if ((err = TAction::checkArgs(key, value, delta)) != GF_NOERR) {
return err;
}
CHECK_DESTROY_PENDING_NOTHROW(shared_lock);
TAction action(*this);
TXState* txState = action.m_txState;
if (txState != nullptr) {
if (isLocalOp(&eventFlags)) {
return GF_NOTSUP;
}
/* adongre - Coverity II
* CID 29194 (6): Parse warning (PW.PARAMETER_HIDDEN)
*/
// std::shared_ptr<VersionTag> versionTag;
err = action.remoteUpdate(key, value, aCallbackArgument, versionTag);
if (err == GF_NOERR) {
txState->setDirty();
}
return err;
}
bool cachingEnabled = m_regionAttributes.getCachingEnabled();
std::shared_ptr<MapEntryImpl> entry;
// do not invoke the writer in case of notification/eviction
// or expiration
if (m_writer != nullptr && eventFlags.invokeCacheWriter()) {
action.getCallbackOldValue(cachingEnabled, key, entry, oldValue);
// invokeCacheWriterForEntryEvent method has the check that if oldValue
// is a CacheableToken then it sets it to nullptr; also determines if it
// should be BEFORE_UPDATE or BEFORE_CREATE depending on oldValue
if (!invokeCacheWriterForEntryEvent(key, oldValue, value, aCallbackArgument,
eventFlags,
TAction::s_beforeEventType)) {
TAction::logCacheWriterFailure(key, oldValue);
return GF_CACHEWRITER_ERROR;
}
}
bool remoteOpDone = false;
// try the remote update; but if this fails (e.g. due to security
// exception) do not do the local update
// uses the technique of adding a tracking to the entry before proceeding
// for put; if the update counter changes when the remote update completes
// then it means that the local entry was overwritten in the meantime
// by a notification or another thread, so we do not do the local update
if (!eventFlags.isLocal() && !eventFlags.isNotification()) {
if (cachingEnabled && updateCount < 0 &&
!m_regionAttributes.getConcurrencyChecksEnabled()) {
// add a tracking for the entry
if ((updateCount = m_entries->addTrackerForEntry(
key, oldValue, TAction::s_addIfAbsent, TAction::s_failIfPresent,
true)) < 0) {
if (oldValue != nullptr) {
// fail for "create" when entry exists
return GF_CACHE_ENTRY_EXISTS;
}
}
}
// propagate the update to remote server, if any
err = action.remoteUpdate(key, value, aCallbackArgument, versionTag);
if (err != GF_NOERR) {
if (updateCount >= 0 &&
!m_regionAttributes.getConcurrencyChecksEnabled()) {
m_entries->removeTrackerForEntry(key);
}
return err;
}
remoteOpDone = true;
}
if (!eventFlags.isNotification() || getProcessedMarker()) {
if ((err = action.localUpdate(key, value, oldValue, cachingEnabled,
eventFlags, updateCount, versionTag, delta,
eventId, remoteOpDone)) ==
GF_CACHE_ENTRY_UPDATED) {
LOGFINEST(
"%s: did not change local value for key [%s] since it has "
"been updated by another thread while operation was in progress",
TAction::name(), Utils::nullSafeToString(key).c_str());
err = GF_NOERR;
} else if (err == GF_CACHE_CONCURRENT_MODIFICATION_EXCEPTION) {
LOGDEBUG(
"Region::localUpdate: updateNoThrow<%s> for key [%s] failed because the cache already contains \
an entry with higher version. The cache listener will not be invoked.",
TAction::name(), Utils::nullSafeToString(key).c_str());
// Cache listener won't be called in this case
return GF_NOERR;
} else if (err == GF_INVALID_DELTA) {
LOGDEBUG(
"Region::localUpdate: updateNoThrow<%s> for key [%s] failed "
"because "
"of invalid delta.",
TAction::name(), Utils::nullSafeToString(key).c_str());
m_cacheImpl->getCachePerfStats().incFailureOnDeltaReceived();
// Get full object from server.
std::shared_ptr<Cacheable>& newValue1 =
const_cast<std::shared_ptr<Cacheable>&>(value);
std::shared_ptr<VersionTag> versionTag1;
err = getNoThrow_FullObject(eventId, newValue1, versionTag1);
if (err == GF_NOERR && newValue1 != nullptr) {
err = m_entries->put(key, newValue1, entry, oldValue, updateCount, 0,
versionTag1 != nullptr ? versionTag1 : versionTag);
if (err == GF_CACHE_CONCURRENT_MODIFICATION_EXCEPTION) {
LOGDEBUG(
"Region::localUpdate: updateNoThrow<%s> for key [%s] failed because the cache already contains \
an entry with higher version. The cache listener will not be invoked.",
TAction::name(), Utils::nullSafeToString(key).c_str());
// Cache listener won't be called in this case
return GF_NOERR;
} else if (err != GF_NOERR) {
return err;
}
}
} else if (err != GF_NOERR) {
return err;
}
} else { // if (getProcessedMarker())
action.getCallbackOldValue(cachingEnabled, key, entry, oldValue);
if (updateCount >= 0 && !m_regionAttributes.getConcurrencyChecksEnabled()) {
m_entries->removeTrackerForEntry(key);
}
}
if (!eventFlags.isNoCallbacks()) {
// invokeCacheListenerForEntryEvent method has the check that if oldValue
// is a CacheableToken then it sets it to nullptr; also determines if it
// should be AFTER_UPDATE or AFTER_CREATE depending on oldValue
err = invokeCacheListenerForEntryEvent(key, oldValue, value,
aCallbackArgument, eventFlags,
TAction::s_afterEventType);
}
return err;
}