use of org.apache.geode.internal.cache.versions.VersionStamp in project geode by apache.
the class AbstractRegionEntry method destroy.
/**
* @throws EntryNotFoundException if expectedOldValue is not null and is not equal to current
* value
*/
@Override
@Released
public boolean destroy(LocalRegion region, EntryEventImpl event, boolean inTokenMode, boolean cacheWrite, @Unretained Object expectedOldValue, boolean forceDestroy, boolean removeRecoveredEntry) throws CacheWriterException, EntryNotFoundException, TimeoutException, RegionClearedException {
// A design decision was made to not retrieve the old value from the disk
// if the entry has been evicted to only have the CacheListener afterDestroy
// method ignore it. We don't want to pay the performance penalty. The
// getValueInVM method does not retrieve the value from disk if it has been
// evicted. Instead, it uses the NotAvailable token.
//
// If the region is a WAN queue region, the old value is actually used by the
// afterDestroy callback on a secondary. It is not needed on a primary.
// Since the destroy that sets WAN_QUEUE_TOKEN always originates on the primary
// we only pay attention to WAN_QUEUE_TOKEN if the event is originRemote.
//
// We also read old value from disk or buffer
// in the case where there is a non-null expectedOldValue
// see PartitionedRegion#remove(Object key, Object value)
ReferenceCountHelper.skipRefCountTracking();
@Retained @Released Object curValue = _getValueRetain(region, true);
ReferenceCountHelper.unskipRefCountTracking();
boolean proceed;
try {
if (curValue == null) {
curValue = Token.NOT_AVAILABLE;
}
if (curValue == Token.NOT_AVAILABLE) {
// the state of the transmitting cache's entry & should be used here
if (event.getCallbackArgument() != null && event.getCallbackArgument().equals(RegionQueue.WAN_QUEUE_TOKEN) && event.isOriginRemote()) {
// check originRemote for bug 40508
// curValue = getValue(region); can cause deadlock if GII is occurring
curValue = getValueOnDiskOrBuffer(region);
} else {
FilterProfile fp = region.getFilterProfile();
if (fp != null && (fp.getCqCount() > 0 || expectedOldValue != null)) {
// curValue = getValue(region); can cause deadlock will fault in the value
// and will confuse LRU.
curValue = getValueOnDiskOrBuffer(region);
}
}
}
if (expectedOldValue != null) {
if (!checkExpectedOldValue(expectedOldValue, curValue, region)) {
throw new EntryNotFoundException(LocalizedStrings.AbstractRegionEntry_THE_CURRENT_VALUE_WAS_NOT_EQUAL_TO_EXPECTED_VALUE.toLocalizedString());
}
}
if (inTokenMode && event.hasOldValue()) {
proceed = true;
} else {
proceed = event.setOldValue(curValue, curValue instanceof GatewaySenderEventImpl) || removeRecoveredEntry || forceDestroy || region.getConcurrencyChecksEnabled() || (event.getOperation() == Operation.REMOVE && (curValue == null || curValue == Token.LOCAL_INVALID || curValue == Token.INVALID));
}
} finally {
OffHeapHelper.releaseWithNoTracking(curValue);
}
if (proceed) {
// after the entry not found exception above.
if (!removeRecoveredEntry) {
region.generateAndSetVersionTag(event, this);
}
if (cacheWrite) {
region.cacheWriteBeforeDestroy(event, expectedOldValue);
if (event.getRegion().getServerProxy() != null) {
// server will return a version tag
// update version information (may throw ConcurrentCacheModificationException)
VersionStamp stamp = getVersionStamp();
if (stamp != null) {
stamp.processVersionTag(event);
}
}
}
region.recordEvent(event);
// RegionEntry (the old value) is invalid
if (!region.isProxy() && !isInvalid()) {
IndexManager indexManager = region.getIndexManager();
if (indexManager != null) {
try {
if (isValueNull()) {
@Released Object value = getValueOffHeapOrDiskWithoutFaultIn(region);
try {
Object preparedValue = prepareValueForCache(region, value, false);
_setValue(preparedValue);
releaseOffHeapRefIfRegionBeingClosedOrDestroyed(region, preparedValue);
} finally {
OffHeapHelper.release(value);
}
}
indexManager.updateIndexes(this, IndexManager.REMOVE_ENTRY, IndexProtocol.OTHER_OP);
} catch (QueryException e) {
throw new IndexMaintenanceException(e);
}
}
}
boolean removeEntry = false;
VersionTag v = event.getVersionTag();
if (region.concurrencyChecksEnabled && !removeRecoveredEntry && !event.isFromRILocalDestroy()) {
// Destroy will write a tombstone instead
if (v == null || !v.hasValidVersion()) {
// localDestroy and eviction and ops received with no version tag
// should create a tombstone using the existing version stamp, as should
// (bug #45245) responses from servers that do not have valid version information
VersionStamp stamp = this.getVersionStamp();
if (stamp != null) {
// proxy has no stamps
v = stamp.asVersionTag();
event.setVersionTag(v);
}
}
removeEntry = v == null || !v.hasValidVersion();
} else {
removeEntry = true;
}
if (removeEntry) {
boolean isThisTombstone = isTombstone();
if (inTokenMode && !event.getOperation().isEviction()) {
setValue(region, Token.DESTROYED);
} else {
removePhase1(region, false);
}
if (isThisTombstone) {
region.unscheduleTombstone(this);
}
} else {
makeTombstone(region, v);
}
return true;
} else {
return false;
}
}
use of org.apache.geode.internal.cache.versions.VersionStamp in project geode by apache.
the class AbstractRegionEntry method processVersionTag.
protected void processVersionTag(EntryEvent cacheEvent, boolean conflictCheck) {
EntryEventImpl event = (EntryEventImpl) cacheEvent;
VersionTag tag = event.getVersionTag();
if (tag == null) {
return;
}
try {
if (tag.isGatewayTag()) {
// this may throw ConcurrentCacheModificationException or modify the event
if (processGatewayTag(cacheEvent)) {
return;
}
assert false : "processGatewayTag failure - returned false";
}
if (!tag.isFromOtherMember()) {
if (!event.getOperation().isNetSearch()) {
// except for netsearch, all locally-generated tags can be ignored
return;
}
}
final InternalDistributedMember originator = (InternalDistributedMember) event.getDistributedMember();
final VersionSource dmId = event.getRegion().getVersionMember();
LocalRegion r = event.getLocalRegion();
boolean eventHasDelta = event.getDeltaBytes() != null && event.getRawNewValue() == null;
VersionStamp stamp = getVersionStamp();
// perform a gateway conflict check
if (stamp != null && !tag.isAllowedByResolver()) {
int stampDsId = stamp.getDistributedSystemId();
int tagDsId = tag.getDistributedSystemId();
if (stampDsId != 0 && stampDsId != tagDsId && stampDsId != -1) {
StringBuilder verbose = null;
if (logger.isTraceEnabled(LogMarker.TOMBSTONE)) {
verbose = new StringBuilder();
verbose.append("processing tag for key " + getKey() + ", stamp=" + stamp.asVersionTag() + ", tag=").append(tag);
}
long stampTime = stamp.getVersionTimeStamp();
long tagTime = tag.getVersionTimeStamp();
if (stampTime > 0 && (tagTime > stampTime || (tagTime == stampTime && tag.getDistributedSystemId() >= stamp.getDistributedSystemId()))) {
if (verbose != null) {
verbose.append(" - allowing event");
logger.trace(LogMarker.TOMBSTONE, verbose);
}
// Update the stamp with event's version information.
applyVersionTag(r, stamp, tag, originator);
return;
}
if (stampTime > 0) {
if (verbose != null) {
verbose.append(" - disallowing event");
logger.trace(LogMarker.TOMBSTONE, verbose);
}
r.getCachePerfStats().incConflatedEventsCount();
persistConflictingTag(r, tag);
throw new ConcurrentCacheModificationException("conflicting event detected");
}
}
}
if (r.getVersionVector() != null && r.getServerProxy() == null && (r.getDataPolicy().withPersistence() || !r.getScope().isLocal())) {
// bug #45258 - perf degradation for local regions and RVV
VersionSource who = tag.getMemberID();
if (who == null) {
who = originator;
}
r.getVersionVector().recordVersion(who, tag);
}
assert !tag.isFromOtherMember() || tag.getMemberID() != null : "remote tag is missing memberID";
// for a long time I had conflict checks turned off in clients when
// receiving a response from a server and applying it to the cache. This lowered
// the CPU cost of versioning but eventually had to be pulled for bug #45453
// events coming from servers while a local sync is held on the entry
// do not require a conflict check. Conflict checks were already
// performed on the server and here we just consume whatever was sent back.
// Event.isFromServer() returns true for client-update messages and
// for putAll/getAll, which do not hold syncs during the server operation.
// for a very long time we had conflict checks turned off for PR buckets.
// Bug 45669 showed a primary dying in the middle of distribution. This caused
// one backup bucket to have a v2. The other bucket was promoted to primary and
// generated a conflicting v2. We need to do the check so that if this second
// v2 loses to the original one in the delta-GII operation that the original v2
// will be the winner in both buckets.
// The new value in event is not from GII, even it could be tombstone
basicProcessVersionTag(r, tag, false, eventHasDelta, dmId, originator, conflictCheck);
} catch (ConcurrentCacheModificationException ex) {
event.isConcurrencyConflict(true);
throw ex;
}
}
use of org.apache.geode.internal.cache.versions.VersionStamp in project geode by apache.
the class AbstractRegionMap method processAndGenerateTXVersionTag.
/**
* called from txApply* methods to process and generate versionTags.
*/
private void processAndGenerateTXVersionTag(final LocalRegion owner, EntryEventImpl cbEvent, RegionEntry re, TXEntryState txEntryState) {
if (shouldPerformConcurrencyChecks(owner, cbEvent)) {
try {
if (txEntryState != null && txEntryState.getRemoteVersionTag() != null) {
// to generate a version based on a remote VersionTag, we will
// have to put the remote versionTag in the regionEntry
VersionTag remoteTag = txEntryState.getRemoteVersionTag();
if (re instanceof VersionStamp) {
VersionStamp stamp = (VersionStamp) re;
stamp.setVersions(remoteTag);
}
}
processVersionTag(re, cbEvent);
} catch (ConcurrentCacheModificationException ignore) {
// ignore this execption, however invoke callbacks for this operation
}
// just apply it and not regenerate it in phase-2 commit
if (cbEvent != null && txEntryState != null && txEntryState.getDistTxEntryStates() != null) {
cbEvent.setNextRegionVersion(txEntryState.getDistTxEntryStates().getRegionVersion());
}
// cbEvent.setNextRegionVersion(txEntryState.getNextRegionVersion());
owner.generateAndSetVersionTag(cbEvent, re);
}
}
use of org.apache.geode.internal.cache.versions.VersionStamp in project geode by apache.
the class BucketRegion method getSerialized.
/**
* Horribly plagiarized from the similar method in LocalRegion
*
* @param key
* @param updateStats
* @param clientEvent holder for client version tag
* @param returnTombstones whether Token.TOMBSTONE should be returned for destroyed entries
* @return serialized form if present, null if the entry is not in the cache, or INVALID or
* LOCAL_INVALID re is a miss (invalid)
* @throws IOException if there is a serialization problem see
* LocalRegion#getDeserializedValue(RegionEntry, KeyInfo, boolean, boolean, boolean,
* EntryEventImpl, boolean, boolean, boolean)
*/
private RawValue getSerialized(Object key, boolean updateStats, boolean doNotLockEntry, EntryEventImpl clientEvent, boolean returnTombstones) throws EntryNotFoundException, IOException {
RegionEntry re = null;
re = this.entries.getEntry(key);
if (re == null) {
return NULLVALUE;
}
if (re.isTombstone() && !returnTombstones) {
return NULLVALUE;
}
Object v = null;
try {
v = re.getValue(this);
if (doNotLockEntry) {
if (v == Token.NOT_AVAILABLE || v == null) {
return REQUIRES_ENTRY_LOCK;
}
}
if (clientEvent != null) {
VersionStamp stamp = re.getVersionStamp();
if (stamp != null) {
clientEvent.setVersionTag(stamp.asVersionTag());
}
}
} catch (DiskAccessException dae) {
this.handleDiskAccessException(dae);
throw dae;
}
if (v == null) {
return NULLVALUE;
} else {
if (updateStats) {
updateStatsForGet(re, true);
}
return new RawValue(v);
}
}
use of org.apache.geode.internal.cache.versions.VersionStamp in project geode by apache.
the class UpdateVersionDUnitTest method testUpdateVersionAfterCreateWithSerialSender.
@Test
public void testUpdateVersionAfterCreateWithSerialSender() {
Host host = Host.getHost(0);
// server1 site1
VM vm0 = host.getVM(0);
// server2 site1
VM vm1 = host.getVM(1);
// server1 site2
VM vm2 = host.getVM(2);
// server2 site2
VM vm3 = host.getVM(3);
final String key = "key-1";
// Site 1
Integer lnPort = (Integer) vm0.invoke(() -> UpdateVersionDUnitTest.createFirstLocatorWithDSId(1));
vm0.invoke(() -> UpdateVersionDUnitTest.createCache(lnPort));
vm0.invoke(() -> UpdateVersionDUnitTest.createSender("ln1", 2, false, 10, 1, false, false, null, true));
vm0.invoke(() -> UpdateVersionDUnitTest.createPartitionedRegion(regionName, "ln1", 1, 1));
vm0.invoke(() -> UpdateVersionDUnitTest.startSender("ln1"));
vm0.invoke(() -> UpdateVersionDUnitTest.waitForSenderRunningState("ln1"));
// Site 2
Integer nyPort = (Integer) vm2.invoke(() -> UpdateVersionDUnitTest.createFirstRemoteLocator(2, lnPort));
Integer nyRecPort = (Integer) vm2.invoke(() -> UpdateVersionDUnitTest.createReceiver(nyPort));
vm2.invoke(() -> UpdateVersionDUnitTest.createPartitionedRegion(regionName, "", 1, 1));
vm3.invoke(() -> UpdateVersionDUnitTest.createCache(nyPort));
vm3.invoke(() -> UpdateVersionDUnitTest.createPartitionedRegion(regionName, "", 1, 1));
final VersionTag tag = (VersionTag) vm0.invoke(new SerializableCallable("Update a single entry and get its version") {
@Override
public Object call() throws CacheException {
Cache cache = CacheFactory.getAnyInstance();
Region region = cache.getRegion(regionName);
assertTrue(region instanceof PartitionedRegion);
region.put(key, "value-1");
region.put(key, "value-2");
Entry entry = region.getEntry(key);
assertTrue(entry instanceof EntrySnapshot);
RegionEntry regionEntry = ((EntrySnapshot) entry).getRegionEntry();
VersionStamp stamp = regionEntry.getVersionStamp();
// Create a duplicate entry version tag from stamp with newer
// time-stamp.
VersionSource memberId = (VersionSource) cache.getDistributedSystem().getDistributedMember();
VersionTag tag = VersionTag.create(memberId);
int entryVersion = stamp.getEntryVersion() - 1;
int dsid = stamp.getDistributedSystemId();
long time = System.currentTimeMillis();
tag.setEntryVersion(entryVersion);
tag.setDistributedSystemId(dsid);
tag.setVersionTimeStamp(time);
tag.setIsRemoteForTesting();
EntryEventImpl event = createNewEvent((PartitionedRegion) region, tag, entry.getKey(), "value-3");
((LocalRegion) region).basicUpdate(event, false, true, 0L, false);
// Verify the new stamp
entry = region.getEntry(key);
assertTrue(entry instanceof EntrySnapshot);
regionEntry = ((EntrySnapshot) entry).getRegionEntry();
stamp = regionEntry.getVersionStamp();
assertEquals("Time stamp did NOT get updated by UPDATE_VERSION operation on LocalRegion", time, stamp.getVersionTimeStamp());
assertEquals(++entryVersion, stamp.getEntryVersion());
assertEquals(dsid, stamp.getDistributedSystemId());
return stamp.asVersionTag();
}
});
VersionTag remoteTag = (VersionTag) vm3.invoke(new SerializableCallable("Get timestamp from remote site") {
@Override
public Object call() throws Exception {
Cache cache = CacheFactory.getAnyInstance();
final PartitionedRegion region = (PartitionedRegion) cache.getRegion(regionName);
// wait for entry to be received
WaitCriterion wc = new WaitCriterion() {
public boolean done() {
Entry<?, ?> entry = null;
try {
entry = region.getDataStore().getEntryLocally(0, key, false, false);
} catch (EntryNotFoundException e) {
// expected
} catch (ForceReattemptException e) {
// expected
} catch (PRLocallyDestroyedException e) {
throw new RuntimeException("unexpected exception", e);
}
if (entry != null) {
LogWriterUtils.getLogWriter().info("found entry " + entry);
}
return (entry != null);
}
public String description() {
return "Expected " + key + " to be received on remote WAN site";
}
};
Wait.waitForCriterion(wc, 30000, 500, true);
wc = new WaitCriterion() {
public boolean done() {
Entry entry = region.getEntry(key);
assertTrue(entry instanceof EntrySnapshot);
RegionEntry regionEntry = ((EntrySnapshot) entry).getRegionEntry();
return regionEntry.getVersionStamp().getVersionTimeStamp() == tag.getVersionTimeStamp();
}
public String description() {
return "waiting for timestamp to be updated";
}
};
Wait.waitForCriterion(wc, 30000, 500, true);
Entry entry = region.getEntry(key);
assertTrue("entry class is wrong: " + entry, entry instanceof EntrySnapshot);
RegionEntry regionEntry = ((EntrySnapshot) entry).getRegionEntry();
VersionStamp stamp = regionEntry.getVersionStamp();
return stamp.asVersionTag();
}
});
assertEquals("Local and remote site have different timestamps", tag.getVersionTimeStamp(), remoteTag.getVersionTimeStamp());
}
Aggregations