You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by kl...@apache.org on 2016/02/08 22:58:36 UTC
[09/50] [abbrv] incubator-geode git commit: GEODE-915: add
FORCE_INVALIDATE_EVENT
GEODE-915: add FORCE_INVALIDATE_EVENT
If the system property gemfire.FORCE_INVALIDATE_EVENT
is set to true then afterInvalidate on CacheListeners will be called even
if the entry does not exist or if the entry is already invalid.
Project: http://git-wip-us.apache.org/repos/asf/incubator-geode/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-geode/commit/f3dd3353
Tree: http://git-wip-us.apache.org/repos/asf/incubator-geode/tree/f3dd3353
Diff: http://git-wip-us.apache.org/repos/asf/incubator-geode/diff/f3dd3353
Branch: refs/heads/feature/GEODE-773-2
Commit: f3dd3353deb154ade18136781cc18308d3f615dd
Parents: e97d746
Author: Darrel Schneider <ds...@pivotal.io>
Authored: Thu Feb 4 16:30:54 2016 -0800
Committer: Darrel Schneider <ds...@pivotal.io>
Committed: Fri Feb 5 08:59:14 2016 -0800
----------------------------------------------------------------------
.../internal/cache/AbstractRegionMap.java | 22 ++-
.../gemfire/internal/cache/LocalRegion.java | 4 +-
.../gemfire/cache30/CacheListenerTestCase.java | 69 +++++++
.../internal/cache/AbstractRegionMapTest.java | 186 +++++++++++++++++++
4 files changed, 278 insertions(+), 3 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/f3dd3353/gemfire-core/src/main/java/com/gemstone/gemfire/internal/cache/AbstractRegionMap.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/internal/cache/AbstractRegionMap.java b/gemfire-core/src/main/java/com/gemstone/gemfire/internal/cache/AbstractRegionMap.java
index 3679519..6fe60ce 100644
--- a/gemfire-core/src/main/java/com/gemstone/gemfire/internal/cache/AbstractRegionMap.java
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/internal/cache/AbstractRegionMap.java
@@ -105,7 +105,7 @@ import com.gemstone.gemfire.pdx.internal.ConvertableToBytes;
// which checks for RegionEntry classes of GFE and validates the same with its
// own classes.
-abstract class AbstractRegionMap implements RegionMap {
+public abstract class AbstractRegionMap implements RegionMap {
private static final Logger logger = LogService.getLogger();
@@ -1953,6 +1953,23 @@ abstract class AbstractRegionMap implements RegionMap {
}
}
+ /**
+ * If true then invalidates that throw EntryNotFoundException
+ * or that are already invalid will first call afterInvalidate on CacheListeners.
+ * The old value on the event passed to afterInvalidate will be null.
+ */
+ public static boolean FORCE_INVALIDATE_EVENT = Boolean.getBoolean("gemfire.FORCE_INVALIDATE_EVENT");
+
+ /**
+ * If the FORCE_INVALIDATE_EVENT flag is true
+ * then invoke callbacks on the given event.
+ */
+ void forceInvalidateEvent(EntryEventImpl event) {
+ if (FORCE_INVALIDATE_EVENT) {
+ event.invokeCallbacks(_getOwner(), false, false);
+ }
+ }
+
public final boolean invalidate(EntryEventImpl event,
boolean invokeCallbacks, boolean forceNewEntry, boolean forceCallbacks)
throws EntryNotFoundException
@@ -2019,6 +2036,7 @@ abstract class AbstractRegionMap implements RegionMap {
// that's okay - when writing an invalid into a disk, the
// region has been cleared (including this token)
}
+ forceInvalidateEvent(event);
} else {
owner.cacheWriteBeforeInvalidate(event, invokeCallbacks, forceNewEntry);
if (owner.concurrencyChecksEnabled && event.noVersionReceivedFromServer()) {
@@ -2247,6 +2265,7 @@ abstract class AbstractRegionMap implements RegionMap {
if (event.getVersionTag() != null && owner.getVersionVector() != null) {
owner.getVersionVector().recordVersion((InternalDistributedMember) event.getDistributedMember(), event.getVersionTag());
}
+ forceInvalidateEvent(event);
}
else { // previous value not invalid
event.setRegionEntry(re);
@@ -2313,6 +2332,7 @@ abstract class AbstractRegionMap implements RegionMap {
// is in region, do nothing
}
if (!entryExisted) {
+ forceInvalidateEvent(event);
owner.checkEntryNotFound(event.getKey());
}
} // while(retry)
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/f3dd3353/gemfire-core/src/main/java/com/gemstone/gemfire/internal/cache/LocalRegion.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/internal/cache/LocalRegion.java b/gemfire-core/src/main/java/com/gemstone/gemfire/internal/cache/LocalRegion.java
index 1c5f321..2092508 100644
--- a/gemfire-core/src/main/java/com/gemstone/gemfire/internal/cache/LocalRegion.java
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/internal/cache/LocalRegion.java
@@ -804,11 +804,11 @@ public class LocalRegion extends AbstractRegion
}
}
- public final IndexUpdater getIndexUpdater() {
+ public IndexUpdater getIndexUpdater() {
return this.entries.getIndexUpdater();
}
- final boolean isCacheClosing()
+ boolean isCacheClosing()
{
return this.cache.isClosed();
}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/f3dd3353/gemfire-core/src/test/java/com/gemstone/gemfire/cache30/CacheListenerTestCase.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/cache30/CacheListenerTestCase.java b/gemfire-core/src/test/java/com/gemstone/gemfire/cache30/CacheListenerTestCase.java
index 9a725e7..4e4147f 100644
--- a/gemfire-core/src/test/java/com/gemstone/gemfire/cache30/CacheListenerTestCase.java
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/cache30/CacheListenerTestCase.java
@@ -19,6 +19,7 @@ package com.gemstone.gemfire.cache30;
import com.gemstone.gemfire.cache.*;
//import com.gemstone.gemfire.cache.util.*;
//import java.util.*;
+import com.gemstone.gemfire.internal.cache.AbstractRegionMap;
/**
* An abstract class whose test methods test the functionality of
@@ -234,11 +235,79 @@ public abstract class CacheListenerTestCase
Region region =
createRegion(name, factory.create());
+ // Does not exist so should not invoke listener
+ try {
+ region.invalidate(key);
+ fail("expected EntryNotFoundException");
+ } catch (EntryNotFoundException expected) {
+ }
+ assertFalse(listener.wasInvoked());
+
region.create(key, value);
assertTrue(listener.wasInvoked());
region.invalidate(key);
assertTrue(listener.wasInvoked());
+
+ // already invalid so should not invoke listener
+ region.invalidate(key);
+ assertFalse(listener.wasInvoked());
}
+
+ public void testCacheListenerAfterInvalidateWithForce() throws CacheException {
+ AbstractRegionMap.FORCE_INVALIDATE_EVENT = true;
+ try {
+ String name = this.getUniqueName();
+ final Object key = this.getUniqueName();
+ final Object value = new Integer(42);
+
+ TestCacheListener listener = new TestCacheListener() {
+ int invalidateCount = 0;
+ public void afterCreate2(EntryEvent event) {
+ // This method will get invoked when the region is populated
+ }
+
+ public void afterInvalidate2(EntryEvent event) {
+ invalidateCount++;
+ assertEquals(key, event.getKey());
+ if (invalidateCount == 2) {
+ assertEquals(value, event.getOldValue());
+ } else {
+ assertNull(event.getOldValue());
+ }
+ assertNull(event.getNewValue());
+ assertFalse(event.isLoad());
+ assertFalse(event.isLocalLoad());
+ assertFalse(event.isNetLoad());
+ assertFalse(event.isNetSearch());
+ }
+ };
+
+ AttributesFactory factory =
+ new AttributesFactory(getRegionAttributes());
+ factory.setCacheListener(listener);
+ Region region =
+ createRegion(name, factory.create());
+
+ // Does not exist but should still invoke listener
+ try {
+ region.invalidate(key);
+ fail("expected EntryNotFoundException");
+ } catch (EntryNotFoundException expected) {
+ }
+ assertTrue(listener.wasInvoked());
+
+ region.create(key, value);
+ assertTrue(listener.wasInvoked());
+ region.invalidate(key);
+ assertTrue(listener.wasInvoked());
+ // already invalid but should still invoke listener
+ region.invalidate(key);
+ assertTrue(listener.wasInvoked());
+ } finally {
+ AbstractRegionMap.FORCE_INVALIDATE_EVENT = false;
+ }
+ }
+
/**
* Tests that the <code>CacheListener</code> is called after a region
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/f3dd3353/gemfire-core/src/test/java/com/gemstone/gemfire/internal/cache/AbstractRegionMapTest.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/internal/cache/AbstractRegionMapTest.java b/gemfire-core/src/test/java/com/gemstone/gemfire/internal/cache/AbstractRegionMapTest.java
new file mode 100644
index 0000000..b54bbe2
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/internal/cache/AbstractRegionMapTest.java
@@ -0,0 +1,186 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.gemstone.gemfire.internal.cache;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import com.gemstone.gemfire.cache.DataPolicy;
+import com.gemstone.gemfire.cache.EntryNotFoundException;
+import com.gemstone.gemfire.cache.Operation;
+import com.gemstone.gemfire.test.junit.categories.UnitTest;
+
+@Category(UnitTest.class)
+public class AbstractRegionMapTest {
+
+ @BeforeClass
+ public static void setUpBeforeClass() throws Exception {
+ }
+
+ @AfterClass
+ public static void tearDownAfterClass() throws Exception {
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ }
+
+ @Test
+ public void invalidateOfNonExistentRegionThrowsEntryNotFound() {
+ TestableAbstractRegionMap arm = new TestableAbstractRegionMap();
+ EntryEventImpl event = createEventForInvalidate(arm.owner);
+ when(arm.owner.isInitialized()).thenReturn(true);
+
+ try {
+ arm.invalidate(event, true, false, false);
+ fail("expected EntryNotFoundException");
+ } catch (EntryNotFoundException expected) {
+ }
+ verify(arm.owner, never()).basicInvalidatePart2(any(), any(), anyBoolean(), anyBoolean());
+ verify(arm.owner, never()).invokeInvalidateCallbacks(any(), any(), anyBoolean());
+ }
+
+ @Test
+ public void invalidateOfNonExistentRegionThrowsEntryNotFoundWithForce() {
+ AbstractRegionMap.FORCE_INVALIDATE_EVENT = true;
+ try {
+ TestableAbstractRegionMap arm = new TestableAbstractRegionMap();
+ EntryEventImpl event = createEventForInvalidate(arm.owner);
+ when(arm.owner.isInitialized()).thenReturn(true);
+
+ try {
+ arm.invalidate(event, true, false, false);
+ fail("expected EntryNotFoundException");
+ } catch (EntryNotFoundException expected) {
+ }
+ verify(arm.owner, never()).basicInvalidatePart2(any(), any(), anyBoolean(), anyBoolean());
+ verify(arm.owner, times(1)).invokeInvalidateCallbacks(any(), any(), anyBoolean());
+ } finally {
+ AbstractRegionMap.FORCE_INVALIDATE_EVENT = false;
+ }
+ }
+
+ @Test
+ public void invalidateOfAlreadyInvalidEntryReturnsFalse() {
+ TestableAbstractRegionMap arm = new TestableAbstractRegionMap();
+ EntryEventImpl event = createEventForInvalidate(arm.owner);
+
+ // invalidate on region that is not initialized should create
+ // entry in map as invalid.
+ try {
+ arm.invalidate(event, true, false, false);
+ fail("expected EntryNotFoundException");
+ } catch (EntryNotFoundException expected) {
+ }
+
+ when(arm.owner.isInitialized()).thenReturn(true);
+ assertFalse(arm.invalidate(event, true, false, false));
+ verify(arm.owner, never()).basicInvalidatePart2(any(), any(), anyBoolean(), anyBoolean());
+ verify(arm.owner, never()).invokeInvalidateCallbacks(any(), any(), anyBoolean());
+ }
+
+ @Test
+ public void invalidateOfAlreadyInvalidEntryReturnsFalseWithForce() {
+ AbstractRegionMap.FORCE_INVALIDATE_EVENT = true;
+ try {
+ TestableAbstractRegionMap arm = new TestableAbstractRegionMap();
+ EntryEventImpl event = createEventForInvalidate(arm.owner);
+
+ // invalidate on region that is not initialized should create
+ // entry in map as invalid.
+ try {
+ arm.invalidate(event, true, false, false);
+ fail("expected EntryNotFoundException");
+ } catch (EntryNotFoundException expected) {
+ }
+
+ when(arm.owner.isInitialized()).thenReturn(true);
+ assertFalse(arm.invalidate(event, true, false, false));
+ verify(arm.owner, never()).basicInvalidatePart2(any(), any(), anyBoolean(), anyBoolean());
+ verify(arm.owner, times(1)).invokeInvalidateCallbacks(any(), any(), anyBoolean());
+ } finally {
+ AbstractRegionMap.FORCE_INVALIDATE_EVENT = false;
+ }
+ }
+
+ private EntryEventImpl createEventForInvalidate(LocalRegion lr) {
+ Object key = "key";
+ when(lr.getKeyInfo(key)).thenReturn(new KeyInfo(key, null, null));
+ return EntryEventImpl.create(lr, Operation.INVALIDATE, key, false, null, true, false);
+ }
+
+ @Test
+ public void invalidateForceNewEntryOfAlreadyInvalidEntryReturnsFalse() {
+ TestableAbstractRegionMap arm = new TestableAbstractRegionMap();
+ EntryEventImpl event = createEventForInvalidate(arm.owner);
+
+ // invalidate on region that is not initialized should create
+ // entry in map as invalid.
+ assertTrue(arm.invalidate(event, true, true, false));
+ verify(arm.owner, times(1)).basicInvalidatePart2(any(), any(), anyBoolean(), anyBoolean());
+
+ when(arm.owner.isInitialized()).thenReturn(true);
+ assertFalse(arm.invalidate(event, true, true, false));
+ verify(arm.owner, times(1)).basicInvalidatePart2(any(), any(), anyBoolean(), anyBoolean());
+ verify(arm.owner, never()).invokeInvalidateCallbacks(any(), any(), anyBoolean());
+ }
+
+ @Test
+ public void invalidateForceNewEntryOfAlreadyInvalidEntryReturnsFalseWithForce() {
+ AbstractRegionMap.FORCE_INVALIDATE_EVENT = true;
+ try {
+ TestableAbstractRegionMap arm = new TestableAbstractRegionMap();
+ EntryEventImpl event = createEventForInvalidate(arm.owner);
+
+ // invalidate on region that is not initialized should create
+ // entry in map as invalid.
+ assertTrue(arm.invalidate(event, true, true, false));
+ verify(arm.owner, times(1)).basicInvalidatePart2(any(), any(), anyBoolean(), anyBoolean());
+ verify(arm.owner, never()).invokeInvalidateCallbacks(any(), any(), anyBoolean());
+
+ when(arm.owner.isInitialized()).thenReturn(true);
+ assertFalse(arm.invalidate(event, true, true, false));
+ verify(arm.owner, times(1)).basicInvalidatePart2(any(), any(), anyBoolean(), anyBoolean());
+ verify(arm.owner, times(1)).invokeInvalidateCallbacks(any(), any(), anyBoolean());
+ } finally {
+ AbstractRegionMap.FORCE_INVALIDATE_EVENT = false;
+ }
+ }
+
+ public static class TestableAbstractRegionMap extends AbstractRegionMap {
+ public LocalRegion owner;
+
+ protected TestableAbstractRegionMap() {
+ super(null);
+ this.owner = mock(LocalRegion.class);
+ when(this.owner.getDataPolicy()).thenReturn(DataPolicy.REPLICATE);
+ doThrow(EntryNotFoundException.class).when(this.owner).checkEntryNotFound(any());
+ initialize(owner, new Attributes(), null, false);
+ }
+ }
+}