@Override
//removed final modifier to allow mock this method
public MVCCEntry wrapEntryForPut(InvocationContext ctx, Object key, InternalCacheEntry icEntry,
boolean undeleteIfNeeded, FlagAffectedCommand cmd, boolean skipRead) {
CacheEntry cacheEntry = getFromContext(ctx, key);
MVCCEntry mvccEntry;
if (cacheEntry != null && cacheEntry.isNull() && !useRepeatableRead) cacheEntry = null;
Metadata providedMetadata = cmd.getMetadata();
if (cacheEntry != null) {
if (useRepeatableRead) {
//sanity check. In repeatable read, we only deal with RepeatableReadEntry and ClusteredRepeatableReadEntry
if (cacheEntry instanceof RepeatableReadEntry) {
mvccEntry = (MVCCEntry) cacheEntry;
} else {
throw new IllegalStateException("Cache entry stored in context should be a RepeatableReadEntry instance " +
"but it is " + cacheEntry.getClass().getCanonicalName());
}
//if the icEntry is not null, then this is a remote get. We need to update the value and the metadata.
if (!mvccEntry.isRemoved() && !mvccEntry.skipLookup() && icEntry != null) {
mvccEntry.setValue(icEntry.getValue());
updateVersion(mvccEntry, icEntry.getMetadata());
}
if (!mvccEntry.isRemoved() && mvccEntry.isNull()) {
//new entry
mvccEntry.setCreated(true);
}
//always update the metadata if needed.
updateMetadata(mvccEntry, providedMetadata);
} else {
//skipRead == true because the key already exists in the context that means the key was previous accessed.
mvccEntry = wrapMvccEntryForPut(ctx, key, cacheEntry, providedMetadata, true);
}
mvccEntry.undelete(undeleteIfNeeded);
} else {
InternalCacheEntry ice = (icEntry == null ? getFromContainer(key, false) : icEntry);
// A putForExternalRead is putIfAbsent, so if key present, do nothing
if (ice != null && cmd.hasFlag(Flag.PUT_FOR_EXTERNAL_READ)) {
// make sure we record this! Null value since this is a forced lock on the key
ctx.putLookedUpEntry(key, null);
if (trace) {
log.tracef("Wrap %s for put. Entry=null", key);
}
return null;
}
mvccEntry = ice != null ?
wrapInternalCacheEntryForPut(ctx, key, ice, providedMetadata, skipRead) :
newMvccEntryForPut(ctx, key, cmd, providedMetadata, skipRead);
}
mvccEntry.copyForUpdate(container);
if (trace) {
log.tracef("Wrap %s for put. Entry=%s", key, mvccEntry);
}
return mvccEntry;
}