Search in sources :

Example 6 with VersionStamp

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;
    }
}
Also used : IndexManager(org.apache.geode.cache.query.internal.index.IndexManager) QueryException(org.apache.geode.cache.query.QueryException) Released(org.apache.geode.internal.offheap.annotations.Released) Retained(org.apache.geode.internal.offheap.annotations.Retained) EntryNotFoundException(org.apache.geode.cache.EntryNotFoundException) GatewaySenderEventImpl(org.apache.geode.internal.cache.wan.GatewaySenderEventImpl) VersionTag(org.apache.geode.internal.cache.versions.VersionTag) StoredObject(org.apache.geode.internal.offheap.StoredObject) VersionStamp(org.apache.geode.internal.cache.versions.VersionStamp) IndexMaintenanceException(org.apache.geode.cache.query.IndexMaintenanceException) Released(org.apache.geode.internal.offheap.annotations.Released)

Example 7 with VersionStamp

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;
    }
}
Also used : InternalDistributedMember(org.apache.geode.distributed.internal.membership.InternalDistributedMember) VersionSource(org.apache.geode.internal.cache.versions.VersionSource) VersionTag(org.apache.geode.internal.cache.versions.VersionTag) VersionStamp(org.apache.geode.internal.cache.versions.VersionStamp) ConcurrentCacheModificationException(org.apache.geode.internal.cache.versions.ConcurrentCacheModificationException)

Example 8 with VersionStamp

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);
    }
}
Also used : VersionTag(org.apache.geode.internal.cache.versions.VersionTag) VersionStamp(org.apache.geode.internal.cache.versions.VersionStamp) ConcurrentCacheModificationException(org.apache.geode.internal.cache.versions.ConcurrentCacheModificationException)

Example 9 with VersionStamp

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);
    }
}
Also used : LockObject(org.apache.geode.internal.cache.partitioned.LockObject) VersionStamp(org.apache.geode.internal.cache.versions.VersionStamp)

Example 10 with VersionStamp

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());
}
Also used : Host(org.apache.geode.test.dunit.Host) VersionStamp(org.apache.geode.internal.cache.versions.VersionStamp) Entry(org.apache.geode.cache.Region.Entry) NonTXEntry(org.apache.geode.internal.cache.LocalRegion.NonTXEntry) WaitCriterion(org.apache.geode.test.dunit.WaitCriterion) VersionSource(org.apache.geode.internal.cache.versions.VersionSource) VM(org.apache.geode.test.dunit.VM) SerializableCallable(org.apache.geode.test.dunit.SerializableCallable) VersionTag(org.apache.geode.internal.cache.versions.VersionTag) EntryNotFoundException(org.apache.geode.cache.EntryNotFoundException) PRLocallyDestroyedException(org.apache.geode.internal.cache.partitioned.PRLocallyDestroyedException) Region(org.apache.geode.cache.Region) Cache(org.apache.geode.cache.Cache) DistributedTest(org.apache.geode.test.junit.categories.DistributedTest) Test(org.junit.Test)

Aggregations

VersionStamp (org.apache.geode.internal.cache.versions.VersionStamp)22 VersionTag (org.apache.geode.internal.cache.versions.VersionTag)19 VersionSource (org.apache.geode.internal.cache.versions.VersionSource)13 NonTXEntry (org.apache.geode.internal.cache.LocalRegion.NonTXEntry)11 Test (org.junit.Test)11 Entry (org.apache.geode.cache.Region.Entry)10 IntegrationTest (org.apache.geode.test.junit.categories.IntegrationTest)6 Cache (org.apache.geode.cache.Cache)4 EntryNotFoundException (org.apache.geode.cache.EntryNotFoundException)4 Region (org.apache.geode.cache.Region)4 ConcurrentCacheModificationException (org.apache.geode.internal.cache.versions.ConcurrentCacheModificationException)4 Host (org.apache.geode.test.dunit.Host)4 SerializableCallable (org.apache.geode.test.dunit.SerializableCallable)4 VM (org.apache.geode.test.dunit.VM)4 WaitCriterion (org.apache.geode.test.dunit.WaitCriterion)4 DistributedTest (org.apache.geode.test.junit.categories.DistributedTest)4 PRLocallyDestroyedException (org.apache.geode.internal.cache.partitioned.PRLocallyDestroyedException)3 ArrayList (java.util.ArrayList)2 InternalDistributedMember (org.apache.geode.distributed.internal.membership.InternalDistributedMember)2 RegionVersionVector (org.apache.geode.internal.cache.versions.RegionVersionVector)2