You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by ds...@apache.org on 2016/05/04 23:50:57 UTC
incubator-geode git commit: GEODE-656: add ReferenceCountHelper junit
tests
Repository: incubator-geode
Updated Branches:
refs/heads/develop fdf9e9aa4 -> 32a698736
GEODE-656: add ReferenceCountHelper junit tests
This closes #135
Project: http://git-wip-us.apache.org/repos/asf/incubator-geode/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-geode/commit/32a69873
Tree: http://git-wip-us.apache.org/repos/asf/incubator-geode/tree/32a69873
Diff: http://git-wip-us.apache.org/repos/asf/incubator-geode/diff/32a69873
Branch: refs/heads/develop
Commit: 32a69873682a91a444b8e41ef92e6768625cfd95
Parents: fdf9e9a
Author: Scott Jewell <sj...@pivotal.io>
Authored: Thu Mar 3 11:26:12 2016 -0800
Committer: Darrel Schneider <ds...@pivotal.io>
Committed: Wed May 4 16:50:12 2016 -0700
----------------------------------------------------------------------
.../internal/offheap/ReferenceCountHelper.java | 218 ++---
.../offheap/ReferenceCountHelperImpl.java | 304 ++++++
.../offheap/ReferenceCountHelperImplTest.java | 974 +++++++++++++++++++
.../offheap/ReferenceCountHelperJUnitTest.java | 208 ++++
4 files changed, 1546 insertions(+), 158 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/32a69873/geode-core/src/main/java/com/gemstone/gemfire/internal/offheap/ReferenceCountHelper.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/com/gemstone/gemfire/internal/offheap/ReferenceCountHelper.java b/geode-core/src/main/java/com/gemstone/gemfire/internal/offheap/ReferenceCountHelper.java
index f6696b0..563ba4d 100644
--- a/geode-core/src/main/java/com/gemstone/gemfire/internal/offheap/ReferenceCountHelper.java
+++ b/geode-core/src/main/java/com/gemstone/gemfire/internal/offheap/ReferenceCountHelper.java
@@ -17,15 +17,9 @@
package com.gemstone.gemfire.internal.offheap;
-import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicInteger;
-import com.gemstone.gemfire.internal.cache.RegionEntry;
-
/**
* This class provides static methods to help
* debug off-heap reference count problems.
@@ -33,48 +27,31 @@ import com.gemstone.gemfire.internal.cache.RegionEntry;
* To enable free operation tracking set: -Dgemfire.trackOffHeapFreedRefCounts=true.
*/
public class ReferenceCountHelper {
- private ReferenceCountHelper() {
- // no instances allowed
- }
- final static private boolean trackRefCounts = Boolean.getBoolean("gemfire.trackOffHeapRefCounts");
- final static private boolean trackFreedRefCounts = Boolean.getBoolean("gemfire.trackOffHeapFreedRefCounts");
- final static private ConcurrentMap<Long, List<RefCountChangeInfo>> stacktraces;
- final static private ConcurrentMap<Long, List<RefCountChangeInfo>> freedStacktraces;
- final static private ThreadLocal<Object> refCountOwner;
- final static private ThreadLocal<AtomicInteger> refCountReenterCount;
- final static private Object SKIP_REF_COUNT_TRACKING = new Object();
- final static private List<RefCountChangeInfo> LOCKED = Collections.emptyList();
-
- static {
- if (trackRefCounts) {
- stacktraces = new ConcurrentHashMap<Long, List<RefCountChangeInfo>>();
- if (trackFreedRefCounts) {
- freedStacktraces = new ConcurrentHashMap<Long, List<RefCountChangeInfo>>();
- } else {
- freedStacktraces = null;
- }
- refCountOwner = new ThreadLocal<Object>();
- refCountReenterCount = new ThreadLocal<AtomicInteger>();
- } else {
- stacktraces = null;
- freedStacktraces = null;
- refCountOwner = null;
- refCountReenterCount = null;
- }
+
+ public static final String TRACK_OFFHEAP_REFERENCES = "gemfire.trackOffHeapRefCounts";
+ public static final String TRACK_OFFHEAP_FREES = "gemfire.trackOffHeapFreedRefCounts";
+
+ private static final ReferenceCountHelperImpl inst = new ReferenceCountHelperImpl(Boolean.getBoolean(TRACK_OFFHEAP_REFERENCES), Boolean.getBoolean(TRACK_OFFHEAP_FREES));
+
+ /* Do not allow any instances */
+ private ReferenceCountHelper() {}
+
+ static ReferenceCountHelperImpl getInstance() {
+ return inst;
}
/**
* Returns true if reference count tracking is enabled.
*/
public static boolean trackReferenceCounts() {
- return trackRefCounts;
+ return getInstance().trackReferenceCounts();
}
/**
* Returns true if free operation tracking is enabled.
*/
public static boolean trackFreedReferenceCounts() {
- return trackFreedRefCounts;
+ return getInstance().trackFreedReferenceCounts();
}
/**
@@ -85,31 +62,7 @@ public class ReferenceCountHelper {
* Calling this method is a noop if !trackReferenceCounts.
*/
public static void setReferenceCountOwner(Object owner) {
- if (trackReferenceCounts()) {
- if (refCountOwner.get() != null) {
- AtomicInteger ai = refCountReenterCount.get();
- if (owner != null) {
- ai.incrementAndGet();
- } else {
- if (ai.decrementAndGet() <= 0) {
- refCountOwner.set(null);
- ai.set(0);
- }
- }
- } else {
- AtomicInteger ai = refCountReenterCount.get();
- if (ai == null) {
- ai = new AtomicInteger(0);
- refCountReenterCount.set(ai);
- }
- if (owner != null) {
- ai.set(1);
- } else {
- ai.set(0);
- }
- refCountOwner.set(owner);
- }
- }
+ getInstance().setReferenceCountOwner(owner);
}
/**
@@ -117,12 +70,7 @@ public class ReferenceCountHelper {
* Calling this method is a noop and returns null if !trackReferenceCounts.
*/
public static Object createReferenceCountOwner() {
- Object result = null;
- if (trackReferenceCounts()) {
- result = new Object();
- setReferenceCountOwner(result);
- }
- return result;
+ return getInstance().createReferenceCountOwner();
}
/**
@@ -134,14 +82,21 @@ public class ReferenceCountHelper {
* after the allocation or free is done.
*/
public static void skipRefCountTracking() {
- setReferenceCountOwner(SKIP_REF_COUNT_TRACKING);
+ getInstance().skipRefCountTracking();
+ }
+
+ /**
+ * Returns true if currently tracking reference counts.
+ */
+ public static boolean isRefCountTracking() {
+ return getInstance().isRefCountTracking();
}
/**
* Call this method to undo a call to skipRefCountTracking.
*/
public static void unskipRefCountTracking() {
- setReferenceCountOwner(null);
+ getInstance().unskipRefCountTracking();
}
/**
@@ -149,89 +104,14 @@ public class ReferenceCountHelper {
* the given Chunk address.
*/
public static List<RefCountChangeInfo> getRefCountInfo(long address) {
- if (!trackReferenceCounts()) return null;
- List<RefCountChangeInfo> result = stacktraces.get(address);
- while (result != null && !stacktraces.replace(address, result, LOCKED)) {
- result = stacktraces.get(address);
- }
- return result;
- }
-
- /**
- * Returns a list of any free operation tracking information.
- * This is used to describe who did the previous free(s) when an extra one
- * ends up being done and fails.
- */
- public static List<RefCountChangeInfo> getFreeRefCountInfo(long address) {
- if (!trackReferenceCounts() || !trackFreedReferenceCounts()) return null;
- return freedStacktraces.get(address);
+ return getInstance().getRefCountInfo(address);
}
/**
* Used internally to report that a reference count has changed.
- */
-
+ */
static void refCountChanged(Long address, boolean decRefCount, int rc) {
- final Object owner = refCountOwner.get();
- if (owner == SKIP_REF_COUNT_TRACKING) {
- return;
- }
- List<RefCountChangeInfo> list = stacktraces.get(address);
- if (list == null) {
- List<RefCountChangeInfo> newList = new ArrayList<RefCountChangeInfo>();
- List<RefCountChangeInfo> old = stacktraces.putIfAbsent(address, newList);
- if (old == null) {
- list = newList;
- } else {
- list = old;
- }
- }
- if (decRefCount) {
- if (owner != null) {
- synchronized (list) {
- for (int i=0; i < list.size(); i++) {
- RefCountChangeInfo info = list.get(i);
- if (owner instanceof RegionEntry) {
- // use identity comparison on region entries since sqlf does some wierd stuff in the equals method
- if (owner == info.getOwner()) {
- if (info.getUseCount() > 0) {
- info.decUseCount();
- } else {
- list.remove(i);
- }
- return;
- }
- } else if (owner.equals(info.getOwner())) {
- if (info.getUseCount() > 0) {
- info.decUseCount();
- } else {
- list.remove(i);
- }
- return;
- }
- }
- }
- }
- }
- if (list == LOCKED) {
- MemoryAllocatorImpl.debugLog("refCount " + (decRefCount ? "deced" : "inced") + " after orphan detected for @" + Long.toHexString(address), true);
- return;
- }
- RefCountChangeInfo info = new RefCountChangeInfo(decRefCount, rc, owner);
- synchronized (list) {
- // if (list.size() == 16) {
- // debugLog("dumping @" + Long.toHexString(address) + " history=" + list, false);
- // list.clear();
- // }
- for (RefCountChangeInfo e: list) {
- if (e.isSameCaller(info)) {
- // No need to add it just increment useCount
- e.incUseCount();
- return;
- }
- }
- list.add(info);
- }
+ getInstance().refCountChanged(address, decRefCount, rc);
}
/**
@@ -239,16 +119,38 @@ public class ReferenceCountHelper {
* that a free has happened of the given address.
*/
static void freeRefCountInfo(Long address) {
- if (!trackReferenceCounts()) return;
- List<RefCountChangeInfo> freedInfo = stacktraces.remove(address);
- if (freedInfo == LOCKED) {
- MemoryAllocatorImpl.debugLog("freed after orphan detected for @" + Long.toHexString(address), true);
- } else if (trackFreedReferenceCounts()) {
- if (freedInfo != null) {
- freedStacktraces.put(address, freedInfo);
- } else {
- freedStacktraces.remove(address);
- }
- }
+ getInstance().freeRefCountInfo(address);
+ }
+
+ /**
+ * Returns the thread local owner
+ */
+ static Object getReferenceCountOwner() {
+ return getInstance().getReferenceCountOwner();
+ }
+
+ /**
+ * Returns the thread local count of the
+ * number of times ref count has been updated
+ */
+ static AtomicInteger getReenterCount() {
+ return getInstance().getReenterCount();
+ }
+
+ /**
+ * Returns a list of any free operation tracking information.
+ * This is used to describe who did the previous free(s) when an extra one
+ * ends up being done and fails.
+ */
+ public static List<RefCountChangeInfo> getFreeRefCountInfo(long address) {
+ return getInstance().getFreeRefCountInfo(address);
+ }
+
+ /**
+ * Returns a list of any reference count tracking information for
+ * the given Chunk address without locking.
+ */
+ static List<RefCountChangeInfo> peekRefCountInfo(long address) {
+ return getInstance().peekRefCountInfo(address);
}
}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/32a69873/geode-core/src/main/java/com/gemstone/gemfire/internal/offheap/ReferenceCountHelperImpl.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/com/gemstone/gemfire/internal/offheap/ReferenceCountHelperImpl.java b/geode-core/src/main/java/com/gemstone/gemfire/internal/offheap/ReferenceCountHelperImpl.java
new file mode 100644
index 0000000..571c2d1
--- /dev/null
+++ b/geode-core/src/main/java/com/gemstone/gemfire/internal/offheap/ReferenceCountHelperImpl.java
@@ -0,0 +1,304 @@
+/*
+ * 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.offheap;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import com.gemstone.gemfire.internal.cache.RegionEntry;
+
+/**
+ * All access to this class should be done through
+ * the static methods of ReferenceCountHelper.
+ */
+class ReferenceCountHelperImpl {
+ private boolean trackRefCounts;
+ private boolean trackFreedRefCounts;
+ private ConcurrentMap<Long, List<RefCountChangeInfo>> stacktraces;
+ private ConcurrentMap<Long, List<RefCountChangeInfo>> freedStacktraces;
+ private ThreadLocal<Object> refCountOwner;
+ private ThreadLocal<AtomicInteger> refCountReenterCount;
+ final static private Object SKIP_REF_COUNT_TRACKING = new Object();
+ final static private List<RefCountChangeInfo> LOCKED = Collections.emptyList();
+
+ ReferenceCountHelperImpl(boolean trackRefCounts, boolean trackFreedRefCounts) {
+ this.trackRefCounts = trackRefCounts;
+ this.trackFreedRefCounts = trackFreedRefCounts;
+ if (trackRefCounts) {
+ stacktraces = new ConcurrentHashMap<Long, List<RefCountChangeInfo>>();
+ if (trackFreedRefCounts) {
+ freedStacktraces = new ConcurrentHashMap<Long, List<RefCountChangeInfo>>();
+ } else {
+ freedStacktraces = null;
+ }
+ refCountOwner = new ThreadLocal<Object>();
+ refCountReenterCount = new ThreadLocal<AtomicInteger>();
+ } else {
+ stacktraces = null;
+ freedStacktraces = null;
+ refCountOwner = null;
+ refCountReenterCount = null;
+ }
+ }
+
+ /**
+ * Returns true if reference count tracking is enabled.
+ */
+ public boolean trackReferenceCounts() {
+ return trackRefCounts;
+ }
+
+ /**
+ * Returns true if free operation tracking is enabled.
+ */
+ public boolean trackFreedReferenceCounts() {
+ return trackFreedRefCounts;
+ }
+
+ /**
+ * Optional call to tell the tracker the logical "owner"
+ * of the reference count. For example you could set
+ * the particular EntryEventImpl instance that incremented
+ * the reference count and is responsible for decrementing it.
+ * Calling this method is a noop if !trackReferenceCounts.
+ */
+ public void setReferenceCountOwner(Object owner) {
+ if (trackReferenceCounts()) {
+ if (refCountOwner.get() != null) {
+ AtomicInteger ai = refCountReenterCount.get();
+ if (owner != null) {
+ ai.incrementAndGet();
+ } else {
+ if (ai.decrementAndGet() <= 0) {
+ refCountOwner.set(null);
+ ai.set(0);
+ }
+ }
+ } else {
+ AtomicInteger ai = refCountReenterCount.get();
+ if (ai == null) {
+ ai = new AtomicInteger(0);
+ refCountReenterCount.set(ai);
+ }
+ if (owner != null) {
+ ai.set(1);
+ } else {
+ ai.set(0);
+ }
+ refCountOwner.set(owner);
+ }
+ }
+ }
+
+ /**
+ * Create, set, and return a generic reference count owner object.
+ * Calling this method is a noop and returns null if !trackReferenceCounts.
+ */
+ public Object createReferenceCountOwner() {
+ Object result = null;
+ if (trackReferenceCounts()) {
+ result = new Object();
+ setReferenceCountOwner(result);
+ }
+ return result;
+ }
+
+ /**
+ * Call this method before incrementing a reference count
+ * if you know that tracking is not needed because you know
+ * that the allocate and free will always be done in the same
+ * code block.
+ * Callers of this method must also call unskipRefCountTracking
+ * after the allocation or free is done.
+ */
+ public void skipRefCountTracking() {
+ setReferenceCountOwner(SKIP_REF_COUNT_TRACKING);
+ }
+
+ /**
+ * Returns true if currently tracking reference counts.
+ */
+ public boolean isRefCountTracking() {
+ if (!trackReferenceCounts()) return false;
+ return !(getReferenceCountOwner()==SKIP_REF_COUNT_TRACKING);
+ }
+
+ /**
+ * Call this method to undo a call to skipRefCountTracking.
+ */
+ public void unskipRefCountTracking() {
+ setReferenceCountOwner(null);
+ }
+
+ /**
+ * Returns a list of any reference count tracking information for
+ * the given Chunk address.
+ */
+ public List<RefCountChangeInfo> getRefCountInfo(long address) {
+ if (!trackReferenceCounts()) return null;
+ List<RefCountChangeInfo> result = stacktraces.get(address);
+
+ getReferenceCountInfoTestHook(stacktraces, address);
+
+ while (result != null && !stacktraces.replace(address, result, LOCKED)) {
+ result = stacktraces.get(address);
+ }
+ return result;
+ }
+
+ /*
+ * This method is overridden during testing to allow simulation of a
+ * concurrent update occurring between stacktraces.get and stacktraces.replace
+ */
+ protected void getReferenceCountInfoTestHook(ConcurrentMap<Long, List<RefCountChangeInfo>> stacktraces, long address) {}
+
+ /**
+ * Returns a list of any reference count tracking information for
+ * the given Chunk address without locking.
+ */
+ public List<RefCountChangeInfo> peekRefCountInfo(long address) {
+ if (!trackReferenceCounts()) return null;
+ return stacktraces.get(address);
+ }
+
+ /**
+ * Used internally to report that a reference count has changed.
+ */
+ void refCountChanged(Long address, boolean decRefCount, int rc) {
+ if (!trackReferenceCounts()) return;
+ final Object owner = refCountOwner.get();
+ if (owner == SKIP_REF_COUNT_TRACKING) {
+ return;
+ }
+ List<RefCountChangeInfo> list = stacktraces.get(address);
+ if (list == null) {
+ List<RefCountChangeInfo> newList = new ArrayList<RefCountChangeInfo>();
+
+ refCountChangedTestHook(address, decRefCount, rc);
+
+ List<RefCountChangeInfo> old = stacktraces.putIfAbsent(address, newList);
+ if (old == null) {
+ list = newList;
+ } else {
+ list = old;
+ }
+ }
+ if (decRefCount) {
+ if (owner != null) {
+ synchronized (list) {
+ for (int i=0; i < list.size(); i++) {
+ RefCountChangeInfo info = list.get(i);
+ if (owner instanceof RegionEntry) {
+ // use identity comparison on region entries since sqlf does some wierd stuff in the equals method
+ if (owner == info.getOwner()) {
+ if (info.getUseCount() > 0) {
+ info.decUseCount();
+ } else {
+ list.remove(i);
+ }
+ return;
+ }
+ } else if (owner.equals(info.getOwner())) {
+ if (info.getUseCount() > 0) {
+ info.decUseCount();
+ } else {
+ list.remove(i);
+ }
+ return;
+ }
+ }
+ }
+ }
+ }
+ if (list == LOCKED) {
+ MemoryAllocatorImpl.debugLog("refCount " + (decRefCount ? "deced" : "inced") + " after orphan detected for @" + Long.toHexString(address), true);
+ return;
+ }
+ RefCountChangeInfo info = new RefCountChangeInfo(decRefCount, rc, owner);
+ synchronized (list) {
+ // if (list.size() == 16) {
+ // debugLog("dumping @" + Long.toHexString(address) + " history=" + list, false);
+ // list.clear();
+ // }
+ for (RefCountChangeInfo e: list) {
+ if (e.isSameCaller(info)) {
+ // No need to add it just increment useCount
+ e.incUseCount();
+ return;
+ }
+ }
+ list.add(info);
+ }
+ }
+
+ /*
+ * This method is overridden during testing to allow simulation
+ * of a race to be the first to reference a given address
+ */
+ protected void refCountChangedTestHook(Long address, boolean decRefCount, int rc) { }
+
+ /**
+ * Called internally when free operations are tracked to record
+ * that a free has happened of the given address.
+ */
+ void freeRefCountInfo(Long address) {
+ if (!trackReferenceCounts()) return;
+ List<RefCountChangeInfo> freedInfo = stacktraces.remove(address);
+ if (freedInfo == LOCKED) {
+ MemoryAllocatorImpl.debugLog("freed after orphan detected for @" + Long.toHexString(address), true);
+ } else if (trackFreedReferenceCounts()) {
+ if (freedInfo != null) {
+ freedStacktraces.put(address, freedInfo);
+ } else {
+ freedStacktraces.remove(address);
+ }
+ }
+ }
+
+ /**
+ * Returns the thread local owner
+ */
+ Object getReferenceCountOwner() {
+ if (!trackReferenceCounts()) return null;
+ return refCountOwner.get();
+ }
+
+ /**
+ * Returns the thread local count of the
+ * number of times ref count has been updated
+ */
+ AtomicInteger getReenterCount() {
+ if (!trackReferenceCounts()) return null;
+ return refCountReenterCount.get();
+ }
+
+ /**
+ * Returns a list of any free operation tracking information.
+ * This is used to describe who did the previous free(s) when an extra one
+ * ends up being done and fails.
+ */
+ public List<RefCountChangeInfo> getFreeRefCountInfo(long address) {
+ if (!trackReferenceCounts() || !trackFreedReferenceCounts()) return null;
+ return freedStacktraces.get(address);
+ }
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/32a69873/geode-core/src/test/java/com/gemstone/gemfire/internal/offheap/ReferenceCountHelperImplTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/com/gemstone/gemfire/internal/offheap/ReferenceCountHelperImplTest.java b/geode-core/src/test/java/com/gemstone/gemfire/internal/offheap/ReferenceCountHelperImplTest.java
new file mode 100644
index 0000000..e43362f
--- /dev/null
+++ b/geode-core/src/test/java/com/gemstone/gemfire/internal/offheap/ReferenceCountHelperImplTest.java
@@ -0,0 +1,974 @@
+/*
+ * 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.offheap;
+
+import static org.junit.Assert.*;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.contrib.java.lang.system.SystemOutRule;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+
+import static org.mockito.Mockito.*;
+
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PowerMockIgnore;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.*;
+
+import com.gemstone.gemfire.internal.cache.RegionEntry;
+import com.gemstone.gemfire.test.junit.categories.UnitTest;
+
+/*
+ * PowerMock used in this test to verify static method MemoryAllocatorImpl.debugLog
+ */
+@Category(UnitTest.class)
+@RunWith(PowerMockRunner.class)
+@PowerMockIgnore({ "*.UnitTest" })
+@PrepareForTest({ MemoryAllocatorImpl.class })
+public class ReferenceCountHelperImplTest {
+
+ ReferenceCountHelperImpl rchi;
+
+ @Rule
+ public SystemOutRule sor = new SystemOutRule();
+
+ @Test
+ public void doTrackReferenceCountsWithTrackRefsTrueAndTrackFreesTrue() {
+ rchi = getTrueTrue();
+ assertTrue(rchi.trackReferenceCounts());
+ }
+
+ @Test
+ public void doTrackReferenceCountsWithTrackRefsTrueAndTrackFreesFalse() {
+ rchi = getTrueFalse();
+ assertTrue(rchi.trackReferenceCounts());
+ }
+
+ @Test
+ public void doTrackReferenceCountsWithTrackRefsFalseAndTrackFreesTrue() {
+ rchi = getFalseTrue();
+ assertFalse(rchi.trackReferenceCounts());
+ }
+
+ @Test
+ public void doTrackReferenceCountsWithTrackRefsFalseAndTrackFreesFalse() {
+ rchi = getFalseFalse();
+ assertFalse(rchi.trackReferenceCounts());
+ }
+
+ @Test
+ public void doTrackFreedReferenceCountsWithTrackRefsTrueAndTrackFreesTrue() {
+ rchi = getTrueTrue();
+ assertTrue(rchi.trackFreedReferenceCounts());
+ }
+
+ @Test
+ public void doTrackFreedReferenceCountsWithTrackRefsTrueAndTrackFreesFalse() {
+ rchi = getTrueFalse();
+ assertFalse(rchi.trackFreedReferenceCounts());
+ }
+
+ @Test
+ public void doTrackFreedReferenceCountsWithTrackRefsFalseAndTrackFreesTrue() {
+ rchi = getFalseTrue();
+ assertTrue(rchi.trackFreedReferenceCounts());
+ }
+
+ @Test
+ public void doTrackFreedReferenceCountsWithTrackRefsFalseAndTrackFreesFalse() {
+ rchi = getFalseFalse();
+ assertFalse(rchi.trackFreedReferenceCounts());
+ }
+
+ @Test
+ public void doSkipRefCountTrackingWithTrackRefsTrueAndTrackFreesTrue() {
+ rchi = getTrueTrue();
+ Object preOwner = rchi.getReferenceCountOwner();
+
+ rchi.skipRefCountTracking();
+ Object postOwner = rchi.getReferenceCountOwner();
+
+ assertTrue(postOwner!=preOwner); // skip sets owner to SKIP_REF_COUNT_TRACKING
+
+ assertFalse(rchi.isRefCountTracking());
+
+ Long address = (long) 0x1000;
+ boolean decRefCount = false;
+ int rc = 1;
+ rchi.refCountChanged(address, decRefCount, rc);
+ List<RefCountChangeInfo> list = rchi.peekRefCountInfo(address);
+ assertEquals(null, list);
+
+ rchi.unskipRefCountTracking();
+ postOwner = rchi.getReferenceCountOwner();
+ assertEquals(postOwner, preOwner);
+
+ assertTrue(rchi.isRefCountTracking());
+ }
+
+ @Test
+ public void doSkipRefCountTrackingWithTrackRefsFalseAndTrackFreesTrue() {
+ rchi = getFalseTrue();
+ Object preOwner = rchi.getReferenceCountOwner();
+ assertEquals(null, preOwner); // getReferenceCountOwner returns null if not tracking
+
+ rchi.skipRefCountTracking();
+ assertFalse(rchi.isRefCountTracking());
+
+ rchi.unskipRefCountTracking();
+ assertFalse(rchi.isRefCountTracking()); // system prop not set
+ }
+
+ @Test
+ public void doSkipRefCountTrackingWithTrackRefsFalseAndTrackFreesFalse() {
+ rchi = getFalseFalse();
+ Object preOwner = rchi.getReferenceCountOwner();
+ assertEquals(null, preOwner); // getReferenceCountOwner returns null if not tracking
+
+ rchi.skipRefCountTracking();
+ assertFalse(rchi.isRefCountTracking());
+
+ rchi.unskipRefCountTracking();
+ assertFalse(rchi.isRefCountTracking()); // system prop not set
+ }
+
+ @Test
+ public void doSkipRefCountTrackingWithTrackRefsTrueAndTrackFreesFalse() {
+ rchi = getTrueFalse();
+ Object preOwner = rchi.getReferenceCountOwner();
+
+ rchi.skipRefCountTracking();
+ Object postOwner = rchi.getReferenceCountOwner();
+
+ assertTrue(postOwner!=preOwner); // skip sets owner to SKIP_REF_COUNT_TRACKING
+
+ assertFalse(rchi.isRefCountTracking());
+
+ rchi.unskipRefCountTracking();
+ postOwner = rchi.getReferenceCountOwner();
+ assertEquals(postOwner, preOwner);
+
+ assertTrue(rchi.isRefCountTracking());
+ }
+
+ @Test
+ public void doSetReferenceCountOwnerWithTrackRefsTrueAndTrackFreesTrue() {
+ rchi = getTrueTrue();
+ String owner = null;
+ rchi.setReferenceCountOwner(owner);
+ AtomicInteger ai = rchi.getReenterCount();
+ assertEquals(0, ai.get());
+
+ owner = new String("SomeOwner");
+ rchi.setReferenceCountOwner(owner);
+ ai = rchi.getReenterCount();
+ assertEquals(1, ai.get());
+ assertEquals(rchi.getReferenceCountOwner(), owner);
+
+ String owner2 = new String("SomeOwner2");
+ rchi.setReferenceCountOwner(owner2);
+ ai = rchi.getReenterCount();
+ assertEquals(2, ai.get());
+ assertTrue(rchi.getReferenceCountOwner()!=owner2); // stays original owner until cnt = 0
+
+ String owner3 = null;
+ rchi.setReferenceCountOwner(owner3);
+ ai = rchi.getReenterCount();
+ assertEquals(1, ai.get());
+ assertEquals(rchi.getReferenceCountOwner(), owner);
+
+ owner = null;
+ rchi.setReferenceCountOwner(owner);
+ ai = rchi.getReenterCount();
+ assertEquals(0, ai.get());
+ assertEquals(rchi.getReferenceCountOwner(), null);
+
+ RegionEntry re = mock(RegionEntry.class);
+ rchi.setReferenceCountOwner(re);
+ ai = rchi.getReenterCount();
+ assertEquals(1, ai.get());
+ assertEquals(rchi.getReferenceCountOwner(), re);
+
+ Long address = (long) 0x1000;
+ boolean decRefCount = false;
+ int rc = 1;
+
+ rchi.refCountChanged(address, decRefCount, rc);
+ List<RefCountChangeInfo> list = rchi.peekRefCountInfo(address);
+ assertEquals(1, list.size());
+ RefCountChangeInfo rcci = list.get(0);
+ assertEquals(0, rcci.getUseCount()); // line 258 of ref cnt helper does not set useCount = 1 when adding new entry?
+
+ rchi.refCountChanged(address, decRefCount, rc);
+ list = rchi.peekRefCountInfo(address);
+ assertEquals(1, list.size());
+ rcci = list.get(0);
+ assertEquals(1, rcci.getUseCount()); // line 258 of ref cnt helper does not set useCount = 1 when adding new entry?
+
+ decRefCount = true;
+ rchi.refCountChanged(address, decRefCount, rc);
+ list = rchi.peekRefCountInfo(address);
+ assertEquals(1, list.size());
+ rcci = list.get(0);
+ assertEquals(0, rcci.getUseCount()); // line 258 of ref cnt helper does not set useCount = 1 when adding new entry?
+
+ rchi.refCountChanged(address, decRefCount, rc);
+ list = rchi.peekRefCountInfo(address);
+ assertEquals(0, list.size());
+
+ }
+
+ @Test
+ public void doSetReferenceCountOwnerWithTrackRefsFalseAndTrackFreesTrue() {
+ rchi = getFalseTrue();
+ String owner = null;
+ rchi.setReferenceCountOwner(owner);
+ assertEquals(rchi.getReferenceCountOwner(), owner);
+ AtomicInteger ai = rchi.getReenterCount();
+ assertEquals(null, ai);
+ }
+
+ @Test
+ public void doSetReferenceCountOwnerWithTrackRefsFalseAndTrackFreesFalse() {
+ rchi = getFalseFalse();
+ String owner = null;
+ rchi.setReferenceCountOwner(owner);
+ assertEquals(rchi.getReferenceCountOwner(), owner);
+ AtomicInteger ai = rchi.getReenterCount();
+ assertEquals(null, ai);
+ }
+
+ @Test
+ public void doSetReferenceCountOwnerWithTrackRefsTrueAndTrackFreesFalse() {
+ rchi = getTrueFalse();
+ String owner = null;
+ rchi.setReferenceCountOwner(owner);
+ AtomicInteger ai = rchi.getReenterCount();
+ assertEquals(0, ai.get());
+
+ owner = new String("SomeOwner");
+ rchi.setReferenceCountOwner(owner);
+ ai = rchi.getReenterCount();
+ assertEquals(1, ai.get());
+ assertEquals(rchi.getReferenceCountOwner(), owner);
+
+ String owner2 = new String("SomeOwner2");
+ rchi.setReferenceCountOwner(owner2);
+ ai = rchi.getReenterCount();
+ assertEquals(2, ai.get());
+ assertTrue(rchi.getReferenceCountOwner()!=owner2); // stays original owner until cnt = 0
+
+ String owner3 = null;
+ rchi.setReferenceCountOwner(owner3);
+ ai = rchi.getReenterCount();
+ assertEquals(1, ai.get());
+ assertEquals(rchi.getReferenceCountOwner(), owner);
+
+ owner = null;
+ rchi.setReferenceCountOwner(owner);
+ ai = rchi.getReenterCount();
+ assertEquals(0, ai.get());
+ assertEquals(rchi.getReferenceCountOwner(), null);
+ }
+
+ @Test
+ public void doCreateReferenceCountOwnerWithTrackRefsTrueAndTrackFreesTrue() {
+ rchi = getTrueTrue();
+ Object owner = rchi.createReferenceCountOwner();
+ assertFalse(owner==null);
+ AtomicInteger ai = rchi.getReenterCount();
+ assertEquals(1, ai.get());
+
+ owner = null;
+ rchi.setReferenceCountOwner(owner);
+ ai = rchi.getReenterCount();
+ assertEquals(0, ai.get());
+ assertEquals(rchi.getReferenceCountOwner(), null);
+ }
+
+ @Test
+ public void doCreateReferenceCountOwnerWithTrackRefsFalseAndTrackFreesTrue() {
+ rchi = getFalseTrue();
+ Object owner = rchi.createReferenceCountOwner();
+ assertTrue(owner==null);
+ }
+
+ @Test
+ public void doCreateReferenceCountOwnerWithTrackRefsFalseAndTrackFreesFalse() {
+ rchi = getFalseFalse();
+ Object owner = rchi.createReferenceCountOwner();
+ assertTrue(owner==null);
+ }
+
+ @Test
+ public void doCreateReferenceCountOwnerWithTrackRefsTrueAndTrackFreesFalse() {
+ rchi = getTrueFalse();
+ Object owner = rchi.createReferenceCountOwner();
+ assertFalse(owner==null);
+ AtomicInteger ai = rchi.getReenterCount();
+ assertEquals(1, ai.get());
+
+ owner = null;
+ rchi.setReferenceCountOwner(owner);
+ ai = rchi.getReenterCount();
+ assertEquals(0, ai.get());
+ assertEquals(rchi.getReferenceCountOwner(), null);
+ }
+
+ @Test
+ public void doRefCountChangedNoOwnerWithTrackRefsTrueAndTrackFreesTrue() {
+ rchi = getTrueTrue();
+ Long address = (long) 0x1000;
+ boolean decRefCount = false;
+ int rc = 1;
+
+ rchi.freeRefCountInfo(address); // quick check of free of nonexistent info
+
+ Object owner = rchi.getReferenceCountOwner();
+ assertTrue(owner==null);
+
+ rchi.refCountChanged(address, decRefCount, rc);
+ List<RefCountChangeInfo> list = rchi.peekRefCountInfo(address);
+ assertEquals(1, list.size());
+ RefCountChangeInfo rcci = list.get(0);
+ assertEquals(0, rcci.getUseCount()); // line 258 of ref cnt helper does not set useCount = 1 when adding new entry?
+
+ rchi.refCountChanged(address, decRefCount, rc);
+ list = rchi.peekRefCountInfo(address);
+ assertEquals(1, list.size());
+ rcci = list.get(0);
+ assertEquals(1, rcci.getUseCount()); // line 258 of ref cnt helper does not set useCount = 1 when adding new entry?
+
+ decRefCount = true;
+ rchi.refCountChanged(address, decRefCount, rc);
+ list = rchi.peekRefCountInfo(address);
+ assertEquals(2, list.size()); // inc and dec are tracked in different changeinfo objects (?)
+ rcci = list.get(1);
+ assertEquals(0, rcci.getUseCount()); // line 258 of ref cnt helper does not set useCount = 1 when adding new entry?
+
+ rchi.refCountChanged(address, decRefCount, rc);
+ list = rchi.peekRefCountInfo(address);
+ assertEquals(2, list.size());
+ rcci = list.get(1);
+ assertEquals(1, rcci.getUseCount()); // line 258 of ref cnt helper does not set useCount = 1 when adding new entry?
+
+ list = rchi.peekRefCountInfo(address);
+ assertEquals(2, list.size()); // list contains 2 entries from inc/dec done above
+
+ List<RefCountChangeInfo> freeInfo = rchi.getFreeRefCountInfo(address);
+ assertEquals(null, freeInfo); // no freeRefCountInfo calls yet
+
+ rchi.freeRefCountInfo(address); // when freed, moved to FreeRefCountInfo list
+
+ List<RefCountChangeInfo> freeInfo2 = rchi.getFreeRefCountInfo(address);
+ assertEquals(2, freeInfo2.size()); // the inc/dec info moved to freeRefCountInfo list
+
+ list = rchi.getRefCountInfo(address);
+ assertEquals(null, list); // the inc/dec ref count list should now be null
+ }
+
+ @Test
+ public void doRefCountChangedNoOwnerWithTrackRefsFalseAndTrackFreesTrue() {
+
+ rchi = getFalseTrue();
+
+ Long address = (long) 0x1000;
+ boolean decRefCount = false;
+ int rc = 1;
+
+ Object owner = rchi.getReferenceCountOwner();
+ assertTrue(owner==null);
+
+ rchi.refCountChanged(address, decRefCount, rc);
+ List<RefCountChangeInfo> list = rchi.peekRefCountInfo(address);
+ assertEquals(null, list);
+
+ decRefCount = true;
+ rchi.refCountChanged(address, decRefCount, rc);
+ list = rchi.peekRefCountInfo(address);
+ assertEquals(null, list);
+
+ List<RefCountChangeInfo> freeInfo = rchi.getFreeRefCountInfo(address);
+ assertEquals(null, freeInfo); // no freeRefCountInfo calls yet
+
+ rchi.freeRefCountInfo(address); // noop when not tracking
+
+ freeInfo = rchi.getFreeRefCountInfo(address);
+ assertEquals(null, freeInfo); // should still be null
+ }
+
+ @Test
+ public void doRefCountChangedNoOwnerWithTrackRefsFalseAndTrackFreesFalse() {
+
+ rchi = getFalseFalse();
+
+ Long address = (long) 0x1000;
+ boolean decRefCount = false;
+ int rc = 1;
+
+ Object owner = rchi.getReferenceCountOwner();
+ assertTrue(owner==null);
+
+ rchi.refCountChanged(address, decRefCount, rc);
+ List<RefCountChangeInfo> list = rchi.peekRefCountInfo(address);
+ assertEquals(null, list);
+
+ decRefCount = true;
+ rchi.refCountChanged(address, decRefCount, rc);
+ list = rchi.peekRefCountInfo(address);
+ assertEquals(null, list);
+
+ List<RefCountChangeInfo> freeInfo = rchi.getFreeRefCountInfo(address);
+ assertEquals(null, freeInfo); // no freeRefCountInfo calls yet
+
+ rchi.freeRefCountInfo(address); // noop when not tracking
+
+ freeInfo = rchi.getFreeRefCountInfo(address);
+ assertEquals(null, freeInfo); // should still be null
+ }
+
+ @Test
+ public void doRefCountChangedNoOwnerWithTrackRefsTrueAndTrackFreesFalse() {
+ rchi = getTrueFalse();
+ Long address = (long) 0x1000;
+ boolean decRefCount = false;
+ int rc = 1;
+
+ Object owner = rchi.getReferenceCountOwner();
+ assertTrue(owner==null);
+
+ rchi.refCountChanged(address, decRefCount, rc);
+ List<RefCountChangeInfo> list = rchi.peekRefCountInfo(address);
+ assertEquals(1, list.size());
+ RefCountChangeInfo rcci = list.get(0);
+ assertEquals(0, rcci.getUseCount()); // line 258 of ref cnt helper does not set useCount = 1 when adding new entry?
+
+ rchi.refCountChanged(address, decRefCount, rc);
+ list = rchi.peekRefCountInfo(address);
+ assertEquals(1, list.size());
+ rcci = list.get(0);
+ assertEquals(1, rcci.getUseCount()); // line 258 of ref cnt helper does not set useCount = 1 when adding new entry?
+
+ decRefCount = true;
+ rchi.refCountChanged(address, decRefCount, rc);
+ list = rchi.peekRefCountInfo(address);
+ assertEquals(2, list.size()); // inc and dec are tracked in different changeinfo objects (?)
+ rcci = list.get(1);
+ assertEquals(0, rcci.getUseCount()); // line 258 of ref cnt helper does not set useCount = 1 when adding new entry?
+
+ rchi.refCountChanged(address, decRefCount, rc);
+ list = rchi.peekRefCountInfo(address);
+ assertEquals(2, list.size());
+ rcci = list.get(1);
+ assertEquals(1, rcci.getUseCount()); // line 258 of ref cnt helper does not set useCount = 1 when adding new entry?
+
+ list = rchi.peekRefCountInfo(address);
+ assertEquals(2, list.size()); // list contains 2 entries from inc/dec done above
+
+ List<RefCountChangeInfo> freeInfo = rchi.getFreeRefCountInfo(address);
+ assertEquals(null, freeInfo); // no freeRefCountInfo calls yet
+
+ rchi.freeRefCountInfo(address); // when freed, moved to FreeRefCountInfo list
+
+ List<RefCountChangeInfo> freeInfo2 = rchi.getFreeRefCountInfo(address);
+ assertEquals(null, freeInfo2); // not tracking freed info
+
+ list = rchi.getRefCountInfo(address);
+ assertEquals(null, list); // the inc/dec ref count list should now be null
+ }
+
+ @Test
+ public void doRefCountChangedWithOwnerWithTrackRefsTrueAndTrackFreesTrue() {
+ rchi = getTrueTrue();
+ Long address = (long) 0x1000;
+ boolean decRefCount = false;
+ int rc = 1;
+
+ Object owner = rchi.createReferenceCountOwner();
+ assertFalse(owner==null);
+
+ AtomicInteger ai = rchi.getReenterCount();
+ assertEquals(1, ai.get());
+
+ owner = null;
+ rchi.setReferenceCountOwner(owner);
+ ai = rchi.getReenterCount();
+ assertEquals(0, ai.get());
+ assertEquals(rchi.getReferenceCountOwner(), null);
+
+ owner = rchi.createReferenceCountOwner();
+ assertFalse(owner==null);
+
+ ai = rchi.getReenterCount();
+ assertEquals(1, ai.get());
+
+ rchi.refCountChanged(address, decRefCount, rc);
+ List<RefCountChangeInfo> list = rchi.peekRefCountInfo(address);
+ assertEquals(1, list.size());
+ RefCountChangeInfo rcci = list.get(0);
+ assertEquals(0, rcci.getUseCount()); // line 258 of ref cnt helper does not set useCount = 1 when adding new entry?
+
+ rchi.refCountChanged(address, decRefCount, rc);
+ list = rchi.peekRefCountInfo(address);
+ assertEquals(1, list.size());
+ rcci = list.get(0);
+ assertEquals(1, rcci.getUseCount()); // line 258 of ref cnt helper does not set useCount = 1 when adding new entry?
+
+ decRefCount = true;
+ rchi.refCountChanged(address, decRefCount, rc);
+ list = rchi.peekRefCountInfo(address);
+ assertEquals(1, list.size()); // inc and dec are tracked in different changeinfo objects (?)
+ rcci = list.get(0);
+ assertEquals(0, rcci.getUseCount()); // line 258 of ref cnt helper does not set useCount = 1 when adding new entry?
+
+ rchi.refCountChanged(address, decRefCount, rc);
+ list = rchi.getRefCountInfo(address);
+ assertEquals(0, list.size());
+ }
+
+ @Test
+ public void doRefCountChangedWithOwnerWithTrackRefsFalseAndTrackFreesTrue() {
+
+ rchi = getFalseTrue();
+
+ Long address = (long) 0x1000;
+ boolean decRefCount = false;
+ int rc = 1;
+
+ Object owner = rchi.createReferenceCountOwner();
+ assertTrue(owner==null);
+
+ rchi.refCountChanged(address, decRefCount, rc);
+ List<RefCountChangeInfo> list = rchi.peekRefCountInfo(address);
+ assertEquals(null, list);
+
+ rchi.refCountChanged(address, decRefCount, rc);
+ list = rchi.peekRefCountInfo(address);
+ assertEquals(null, list);
+
+ decRefCount = true;
+ rchi.refCountChanged(address, decRefCount, rc);
+ list = rchi.peekRefCountInfo(address);
+ assertEquals(null, list); // inc and dec are tracked in different changeinfo objects (?)
+
+ rchi.refCountChanged(address, decRefCount, rc);
+ list = rchi.peekRefCountInfo(address);
+ assertEquals(null, list);
+
+ List<RefCountChangeInfo> freeInfo = rchi.getFreeRefCountInfo(address);
+ assertEquals(null, freeInfo); // no freeRefCountInfo calls yet
+
+ rchi.freeRefCountInfo(address); // when freed, moved to FreeRefCountInfo list
+
+ freeInfo = rchi.getFreeRefCountInfo(address);
+ assertEquals(null, freeInfo); // the inc/dec info moved to freeRefCountInfo list
+ }
+
+ @Test
+ public void doRefCountChangedWithOwnerWithTrackRefsFalseAndTrackFreesFalse() {
+
+ rchi = getFalseFalse();
+
+ Long address = (long) 0x1000;
+ boolean decRefCount = false;
+ int rc = 1;
+
+ Object owner = rchi.createReferenceCountOwner();
+ assertTrue(owner==null);
+
+ rchi.refCountChanged(address, decRefCount, rc);
+ List<RefCountChangeInfo> list = rchi.peekRefCountInfo(address);
+ assertEquals(null, list);
+
+ rchi.refCountChanged(address, decRefCount, rc);
+ list = rchi.peekRefCountInfo(address);
+ assertEquals(null, list);
+
+ decRefCount = true;
+ rchi.refCountChanged(address, decRefCount, rc);
+ list = rchi.peekRefCountInfo(address);
+ assertEquals(null, list); // inc and dec are tracked in different changeinfo objects (?)
+
+ rchi.refCountChanged(address, decRefCount, rc);
+ list = rchi.peekRefCountInfo(address);
+ assertEquals(null, list);
+
+ List<RefCountChangeInfo> freeInfo = rchi.getFreeRefCountInfo(address);
+ assertEquals(null, freeInfo); // no freeRefCountInfo calls yet
+
+ rchi.freeRefCountInfo(address); // when freed, moved to FreeRefCountInfo list
+
+ freeInfo = rchi.getFreeRefCountInfo(address);
+ assertEquals(null, freeInfo); // the inc/dec info moved to freeRefCountInfo list
+ }
+
+ @Test
+ public void doRefCountChangedWithOwnerWithTrackRefsTrueAndTrackFreesFalse() {
+ rchi = getTrueFalse();
+ Long address = (long) 0x1000;
+ boolean decRefCount = false;
+ int rc = 1;
+
+ Object owner = rchi.createReferenceCountOwner();
+ assertFalse(owner==null);
+
+ AtomicInteger ai = rchi.getReenterCount();
+ assertEquals(1, ai.get());
+
+ owner = null;
+ rchi.setReferenceCountOwner(owner);
+ ai = rchi.getReenterCount();
+ assertEquals(0, ai.get());
+ assertEquals(rchi.getReferenceCountOwner(), null);
+
+ owner = rchi.createReferenceCountOwner();
+ assertFalse(owner==null);
+
+ ai = rchi.getReenterCount();
+ assertEquals(1, ai.get());
+
+ rchi.refCountChanged(address, decRefCount, rc);
+ List<RefCountChangeInfo> list = rchi.peekRefCountInfo(address);
+ assertEquals(1, list.size());
+ RefCountChangeInfo rcci = list.get(0);
+ assertEquals(0, rcci.getUseCount()); // line 258 of ref cnt helper does not set useCount = 1 when adding new entry?
+
+ rchi.refCountChanged(address, decRefCount, rc);
+ list = rchi.peekRefCountInfo(address);
+ assertEquals(1, list.size());
+ rcci = list.get(0);
+ assertEquals(1, rcci.getUseCount()); // line 258 of ref cnt helper does not set useCount = 1 when adding new entry?
+
+ decRefCount = true;
+ rchi.refCountChanged(address, decRefCount, rc);
+ list = rchi.peekRefCountInfo(address);
+ assertEquals(1, list.size()); // inc and dec are tracked in different changeinfo objects (?)
+ rcci = list.get(0);
+ assertEquals(0, rcci.getUseCount()); // line 258 of ref cnt helper does not set useCount = 1 when adding new entry?
+
+ rchi.refCountChanged(address, decRefCount, rc);
+ list = rchi.peekRefCountInfo(address);
+ assertEquals(0, list.size());
+ }
+
+ @Test
+ public void doGetRefCountInfoWithTrackRefsTrueAndTrackFreesTrue() {
+ rchi = getTrueTrue();
+ long address = (long) 0x1000;
+ boolean decRefCount = false;
+ int rc = 1;
+
+ List<RefCountChangeInfo> list = null;
+
+ rchi.refCountChanged(address, decRefCount, rc);
+ list = rchi.peekRefCountInfo(address);
+ assertEquals(1, list.size());
+ RefCountChangeInfo rcci = list.get(0);
+ assertEquals(0, rcci.getUseCount()); // line 258 of ref cnt helper does not set useCount = 1 when adding new entry?
+
+ rchi.refCountChanged(address, decRefCount, rc);
+ list = rchi.peekRefCountInfo(address);
+ assertEquals(1, list.size());
+ rcci = list.get(0);
+ assertEquals(1, rcci.getUseCount()); // line 258 of ref cnt helper does not set useCount = 1 when adding new entry?
+
+ List<RefCountChangeInfo> info = rchi.getRefCountInfo(address); // now getRefCountInfo
+ assertEquals(1, info.size());
+ rcci = info.get(0);
+ assertEquals(1, rcci.getUseCount());
+
+ list = rchi.peekRefCountInfo(address);
+ assertEquals(0, list.size()); // getRefCountInfo leaves list LOCKED (i.e. empty)
+ }
+
+ @Test
+ public void doRefCountChangedAfterGetRefCountInfoWithTrackRefsTrueAndTrackFreesTrue() throws Exception {
+ rchi = getTrueTrue();
+ long address = (long) 0x1000;
+ boolean decRefCount = false;
+ int rc = 1;
+
+ List<RefCountChangeInfo> list = null;
+
+ rchi.refCountChanged(address, decRefCount, rc);
+ list = rchi.peekRefCountInfo(address);
+ assertEquals(1, list.size());
+ RefCountChangeInfo rcci = list.get(0);
+ assertEquals(0, rcci.getUseCount()); // line 258 of ref cnt helper does not set useCount = 1 when adding new entry?
+
+ rchi.refCountChanged(address, decRefCount, rc);
+ list = rchi.peekRefCountInfo(address);
+ assertEquals(1, list.size());
+ rcci = list.get(0);
+ assertEquals(1, rcci.getUseCount()); // line 258 of ref cnt helper does not set useCount = 1 when adding new entry?
+
+ List<RefCountChangeInfo> info = rchi.getRefCountInfo(address); // now getRefCountInfo
+ assertEquals(1, info.size());
+ rcci = info.get(0);
+ assertEquals(1, rcci.getUseCount());
+
+ list = rchi.peekRefCountInfo(address);
+ assertEquals(0, list.size()); // getRefCountInfo leaves list LOCKED (i.e. empty)
+
+ sor.mute(); // Mute system out
+
+ PowerMockito.spy(MemoryAllocatorImpl.class); // Watch the impl for invocation of debugLog
+
+ rchi.refCountChanged(address, decRefCount, rc); // this line should fail. no inc after getInfo allowed
+ PowerMockito.verifyStatic();
+ MemoryAllocatorImpl.debugLog("refCount inced after orphan detected for @1000", true);
+
+ decRefCount = true;
+
+ rchi.refCountChanged(address, decRefCount, rc); // this line should fail. no inc after getInfo allowed
+ PowerMockito.verifyStatic();
+ MemoryAllocatorImpl.debugLog("refCount deced after orphan detected for @1000", true);
+
+ rchi.freeRefCountInfo(address); // this line should fail. no free after getInfo allowed
+ PowerMockito.verifyStatic();
+ MemoryAllocatorImpl.debugLog("freed after orphan detected for @1000", true);
+
+ }
+
+ @Test
+ public void doGetRefCountInfoWithTrackRefsFalseAndTrackFreesTrue() {
+ rchi = getFalseTrue();
+ long address = (long) 0x1000;
+ boolean decRefCount = false;
+ int rc = 1;
+
+ List<RefCountChangeInfo> list = rchi.getRefCountInfo(address);
+ assertEquals(null, list);
+
+ rchi.refCountChanged(address, decRefCount, rc);
+ list = rchi.peekRefCountInfo(address);
+ assertEquals(null, list);
+
+ List<RefCountChangeInfo> info = rchi.getRefCountInfo(address);
+ assertEquals(null, info);
+
+ list = rchi.peekRefCountInfo(address);
+ assertEquals(null, list);
+
+ rchi.refCountChanged(address, decRefCount, rc); // this will be ignored.
+ decRefCount = true;
+ rchi.refCountChanged(address, decRefCount, rc); // this will be ignored.
+ rchi.freeRefCountInfo(address); // this will be ignored.
+
+ }
+
+ @Test
+ public void doGetRefCountInfoWithTrackRefsFalseAndTrackFreesFalse() {
+ rchi = getFalseFalse();
+ long address = (long) 0x1000;
+ boolean decRefCount = false;
+ int rc = 1;
+
+ List<RefCountChangeInfo> list = rchi.getRefCountInfo(address);
+ assertEquals(null, list);
+
+ rchi.refCountChanged(address, decRefCount, rc);
+ list = rchi.peekRefCountInfo(address);
+ assertEquals(null, list);
+
+ List<RefCountChangeInfo> info = rchi.getRefCountInfo(address);
+ assertEquals(null, info);
+
+ list = rchi.peekRefCountInfo(address);
+ assertEquals(null, list);
+ }
+
+ @Test
+ public void doGetRefCountInfoWithTrackRefsTrueAndTrackFreesFalse() {
+ rchi = getTrueFalse();
+ long address = (long) 0x1000;
+ boolean decRefCount = false;
+ int rc = 1;
+
+ List<RefCountChangeInfo> list = null;
+
+ rchi.refCountChanged(address, decRefCount, rc);
+ list = rchi.peekRefCountInfo(address);
+ assertEquals(1, list.size());
+ RefCountChangeInfo rcci = list.get(0);
+ assertEquals(0, rcci.getUseCount()); // line 258 of ref cnt helper does not set useCount = 1 when adding new entry?
+
+ rchi.refCountChanged(address, decRefCount, rc);
+ list = rchi.peekRefCountInfo(address);
+ assertEquals(1, list.size());
+ rcci = list.get(0);
+ assertEquals(1, rcci.getUseCount()); // line 258 of ref cnt helper does not set useCount = 1 when adding new entry?
+
+ List<RefCountChangeInfo> info = rchi.getRefCountInfo(address); // now getRefCountInfo
+ assertEquals(1, info.size());
+ rcci = info.get(0);
+ assertEquals(1, rcci.getUseCount());
+
+ list = rchi.peekRefCountInfo(address);
+ assertEquals(0, list.size()); // getRefCountInfo leaves list LOCKED (i.e. empty)
+ }
+
+ private ReferenceCountHelperImpl getTrueTrue() {
+ return new ReferenceCountHelperImpl(true, true);
+ }
+
+ private ReferenceCountHelperImpl getTrueFalse() {
+ return new ReferenceCountHelperImpl(true, false);
+ }
+
+ private ReferenceCountHelperImpl getFalseTrue() {
+ return new ReferenceCountHelperImpl(false, true);
+ }
+
+ private ReferenceCountHelperImpl getFalseFalse() {
+ return new ReferenceCountHelperImpl(false, false);
+ }
+
+ private ReferenceCountHelperImpl getHookedImpl() {
+ return new HookedReferenceCountHelperImpl(true, true);
+ }
+
+ @Test
+ public void doGetRefCountInfoNonRegionEntryConcurrencyTest() {
+ rchi = getHookedImpl();
+ long address = (long) 0x1000;
+ int rc = 1;
+ RefCountChangeInfo rcci;
+
+ List<RefCountChangeInfo> list = null;
+
+ rchi.setReferenceCountOwner("TestOwner"); // assume test identity
+
+ rchi.refCountChanged(address, false, rc);
+ list = rchi.peekRefCountInfo(address);
+ assertEquals(1, list.size());
+ rcci = list.get(0);
+ assertEquals(1, rcci.getUseCount()); // hooked impl simulates a concurrent update, so cnt is > expected
+
+ rchi.setReferenceCountOwner(null); // sets owner to null and resets count
+ rchi.setReferenceCountOwner(null); // sets owner to null and resets count
+
+ rchi.setReferenceCountOwner("TestOwner2"); // assume new identity
+
+ rchi.refCountChanged(address, false, rc);
+ list = rchi.peekRefCountInfo(address);
+ assertEquals(1, list.size());
+ rcci = list.get(0);
+ assertEquals(2, rcci.getUseCount()); // list is not null, so hook not used
+
+ rchi.refCountChanged(address, true, rc); // dec ref count
+ list = rchi.peekRefCountInfo(address);
+ assertEquals(2, list.size()); // dec adds new list of stack traces
+ rcci = list.get(1);
+ assertEquals(0, rcci.getUseCount()); // cnt starts at 0 for new entries
+
+ List<RefCountChangeInfo> info = rchi.getRefCountInfo(address); // now getRefCountInfo
+ assertEquals(3, info.size()); // hooked impl added one to list
+ rcci = info.get(2);
+ assertEquals(0, rcci.getUseCount()); // count starts at 0 for new entries
+
+ list = rchi.peekRefCountInfo(address);
+ assertEquals(0, list.size()); // getRefCountInfo leaves list LOCKED (i.e. empty)
+ }
+
+ @Test
+ public void doGetRefCountInfoRegionEntryConcurrencyTest() {
+ rchi = getHookedImpl();
+ long address = (long) 0x1000;
+ int rc = 1;
+ RefCountChangeInfo rcci;
+
+ List<RefCountChangeInfo> list = null;
+
+ RegionEntry re = mock(RegionEntry.class);
+ rchi.setReferenceCountOwner(re); // set owner to region entry type
+
+ rchi.refCountChanged(address, false, rc);
+ list = rchi.peekRefCountInfo(address);
+ assertEquals(1, list.size());
+ rcci = list.get(0);
+ assertEquals(1, rcci.getUseCount()); // hooked impl simulates a concurrent update, so cnt is > expected
+
+ rchi.setReferenceCountOwner(null); // sets owner to null and resets count
+ rchi.setReferenceCountOwner(null); // sets owner to null and resets count
+
+ RegionEntry re2 = mock(RegionEntry.class);
+ rchi.setReferenceCountOwner(re2); // set owner to region entry type
+
+ rchi.refCountChanged(address, false, rc);
+ list = rchi.peekRefCountInfo(address);
+ assertEquals(1, list.size());
+ rcci = list.get(0);
+ assertEquals(2, rcci.getUseCount()); // list is not null, so hook not used
+
+ rchi.refCountChanged(address, true, rc); // dec ref count
+ list = rchi.peekRefCountInfo(address);
+ assertEquals(2, list.size()); // dec adds new list of stack traces
+ rcci = list.get(1);
+ assertEquals(0, rcci.getUseCount()); // cnt starts at 0 for new entries
+
+ List<RefCountChangeInfo> info = rchi.getRefCountInfo(address); // now getRefCountInfo
+ assertEquals(3, info.size()); // hooked impl added one to list
+ rcci = info.get(2);
+ assertEquals(0, rcci.getUseCount()); // count starts at 0 for new entries
+
+ list = rchi.peekRefCountInfo(address);
+ assertEquals(0, list.size()); // getRefCountInfo leaves list LOCKED (i.e. empty)
+ }
+
+ private class HookedReferenceCountHelperImpl extends ReferenceCountHelperImpl {
+ HookedReferenceCountHelperImpl(boolean trackRefCounts, boolean trackFreedRefCounts) {
+ super(trackRefCounts, trackFreedRefCounts);
+ }
+
+ protected int refCountChangedTestHookCount = 0;
+
+ /*
+ * Update list of stack traces for address.
+ * Hooked SUT should see that the list changed.
+ */
+ @Override
+ protected void getReferenceCountInfoTestHook(ConcurrentMap<Long, List<RefCountChangeInfo>> stacktraces, long address) {
+ List<RefCountChangeInfo> updatedList = new ArrayList<RefCountChangeInfo>(stacktraces.get(address));
+ RefCountChangeInfo rcci = new RefCountChangeInfo(false, 0, "TestOwner");
+ updatedList.add(rcci);
+ stacktraces.put(address, updatedList);
+ }
+ /*
+ * Reinvoke refCountChanged to update reference count.
+ * Hooked SUT should see that the count has changed.
+ */
+ @Override
+ protected void refCountChangedTestHook(Long address, boolean decRefCount, int rc) {
+ if(refCountChangedTestHookCount==0) {
+ refCountChangedTestHookCount++;
+ refCountChanged(address, decRefCount, rc);
+ } else {
+ refCountChangedTestHookCount--;
+ }
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/32a69873/geode-core/src/test/java/com/gemstone/gemfire/internal/offheap/ReferenceCountHelperJUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/com/gemstone/gemfire/internal/offheap/ReferenceCountHelperJUnitTest.java b/geode-core/src/test/java/com/gemstone/gemfire/internal/offheap/ReferenceCountHelperJUnitTest.java
new file mode 100644
index 0000000..3b38c8c
--- /dev/null
+++ b/geode-core/src/test/java/com/gemstone/gemfire/internal/offheap/ReferenceCountHelperJUnitTest.java
@@ -0,0 +1,208 @@
+/*
+ * 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.offheap;
+
+import static org.junit.Assert.*;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+
+import com.gemstone.gemfire.test.junit.categories.UnitTest;
+
+import org.mockito.Mockito;
+import static org.mockito.Mockito.*;
+
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PowerMockIgnore;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.*;
+
+/*
+ * This test simply verifies the static class delegates properly to the impl
+ *
+ * PowerMock used in this test to inject mocked impl into static class
+ * The PowerMockRule bootstraps PowerMock without the need for
+ * the @RunWith(PowerMockRunner.class) annotation, which was interfering with jacoco
+ *
+ */
+@Category(UnitTest.class)
+@RunWith(PowerMockRunner.class)
+@PowerMockIgnore({ "*.UnitTest" })
+@PrepareForTest({ ReferenceCountHelper.class })
+public class ReferenceCountHelperJUnitTest {
+
+ private ReferenceCountHelperImpl prepareInstance() {
+ ReferenceCountHelperImpl rchi = mock(ReferenceCountHelperImpl.class);
+ PowerMockito.mockStatic(ReferenceCountHelper.class, Mockito.CALLS_REAL_METHODS);
+ PowerMockito.when(ReferenceCountHelper.getInstance()).thenReturn(rchi);
+ return rchi;
+ }
+
+ @Test
+ public void trackReferenceCountsTrueTest() throws Exception {
+ ReferenceCountHelperImpl rchi = prepareInstance();
+ when(rchi.trackReferenceCounts()).thenReturn(true);
+ boolean b = ReferenceCountHelper.trackReferenceCounts();
+ assertTrue(b);
+ verify(rchi).trackReferenceCounts();
+ }
+
+ @Test
+ public void trackReferenceCountsFalseTest() throws Exception {
+ ReferenceCountHelperImpl rchi = prepareInstance();
+ when(rchi.trackReferenceCounts()).thenReturn(false);
+ boolean b = ReferenceCountHelper.trackReferenceCounts();
+ assertFalse(b);
+ verify(rchi).trackReferenceCounts();
+ }
+
+ @Test
+ public void trackFreedReferenceCountsTrueTest() throws Exception {
+ ReferenceCountHelperImpl rchi = prepareInstance();
+ when(rchi.trackFreedReferenceCounts()).thenReturn(true);
+ assertTrue(ReferenceCountHelper.trackFreedReferenceCounts());
+ verify(rchi).trackFreedReferenceCounts();
+ }
+
+ @Test
+ public void trackFreedReferenceCountsFalseTest() throws Exception {
+ ReferenceCountHelperImpl rchi = prepareInstance();
+ when(rchi.trackFreedReferenceCounts()).thenReturn(false);
+ assertFalse(ReferenceCountHelper.trackFreedReferenceCounts());
+ verify(rchi).trackFreedReferenceCounts();
+ }
+
+ @Test
+ public void setReferenceCountOwnerTest() throws Exception {
+ ReferenceCountHelperImpl rchi = prepareInstance();
+ Object theOwner = new Object();
+ ReferenceCountHelper.setReferenceCountOwner(theOwner);
+ verify(rchi).setReferenceCountOwner(theOwner);
+ }
+
+ @Test
+ public void createReferenceCountOwnerTest() throws Exception {
+ ReferenceCountHelperImpl rchi = prepareInstance();
+ Object expectedResult = new String("createReferenceCountOwner result");
+ when(rchi.createReferenceCountOwner()).thenReturn(expectedResult);
+ Object s = ReferenceCountHelper.createReferenceCountOwner();
+ assertEquals(s, expectedResult);
+ verify(rchi).createReferenceCountOwner();
+ }
+
+ @Test
+ public void skipRefCountTrackingTest() throws Exception {
+ ReferenceCountHelperImpl rchi = prepareInstance();
+ ReferenceCountHelper.skipRefCountTracking();
+ verify(rchi).skipRefCountTracking();
+ }
+
+ @Test
+ public void isRefCountTrackingTrueTest() throws Exception {
+ ReferenceCountHelperImpl rchi = prepareInstance();
+ when(rchi.isRefCountTracking()).thenReturn(true);
+ boolean b = ReferenceCountHelper.isRefCountTracking();
+ assertTrue(b);
+ verify(rchi).isRefCountTracking();
+ }
+
+ @Test
+ public void isRefCountTrackingFalseTest() throws Exception {
+ ReferenceCountHelperImpl rchi = prepareInstance();
+ when(rchi.isRefCountTracking()).thenReturn(false);
+ boolean b = ReferenceCountHelper.isRefCountTracking();
+ assertFalse(b);
+ verify(rchi).isRefCountTracking();
+ }
+
+ @Test
+ public void unskipRefCountTrackingTest() throws Exception {
+ ReferenceCountHelperImpl rchi = prepareInstance();
+ ReferenceCountHelper.unskipRefCountTracking();
+ verify(rchi).unskipRefCountTracking();
+ }
+
+ @Test
+ public void getRefCountInfoTest() throws Exception {
+ ReferenceCountHelperImpl rchi = prepareInstance();
+ List<RefCountChangeInfo> expectedResult = Collections.emptyList();
+ when(rchi.getRefCountInfo((long)1000)).thenReturn(expectedResult);
+ List<RefCountChangeInfo> l = ReferenceCountHelper.getRefCountInfo(1000);
+ assertEquals(l, expectedResult);
+ verify(rchi).getRefCountInfo(1000);
+ }
+
+ @Test
+ public void refCountChangedTest() throws Exception {
+ ReferenceCountHelperImpl rchi = prepareInstance();
+ ReferenceCountHelper.refCountChanged((long)1000, true, 4);
+ verify(rchi).refCountChanged((long)1000, true, 4);
+ }
+
+ @Test
+ public void freeRefCountInfoTest() throws Exception {
+ ReferenceCountHelperImpl rchi = prepareInstance();
+ ReferenceCountHelper.freeRefCountInfo((long)1000);
+ verify(rchi).freeRefCountInfo((long)1000);
+ }
+
+ @Test
+ public void getReferenceCountOwnerTest() throws Exception {
+ ReferenceCountHelperImpl rchi = prepareInstance();
+ Object expectedResult = new String("getReferenceCountOwner result");
+ when(rchi.getReferenceCountOwner()).thenReturn(expectedResult);
+ Object o = ReferenceCountHelper.getReferenceCountOwner();
+ assertEquals(o, expectedResult);
+ verify(rchi).getReferenceCountOwner();
+ }
+
+ @Test
+ public void getReenterCountTest() throws Exception {
+ ReferenceCountHelperImpl rchi = prepareInstance();
+ AtomicInteger expectedResult = new AtomicInteger(8);
+ when(rchi.getReenterCount()).thenReturn(expectedResult);
+ AtomicInteger ai = ReferenceCountHelper.getReenterCount();
+ assertEquals(ai, expectedResult);
+ verify(rchi).getReenterCount();
+ }
+
+ @Test
+ public void getFreeRefCountInfoTest() throws Exception {
+ ReferenceCountHelperImpl rchi = prepareInstance();
+ List<RefCountChangeInfo> expectedResult = Collections.emptyList();
+ when(rchi.getFreeRefCountInfo((long) 1000)).thenReturn(expectedResult);
+ List<RefCountChangeInfo> l = ReferenceCountHelper.getFreeRefCountInfo(1000);
+ assertEquals(l, expectedResult);
+ verify(rchi).getFreeRefCountInfo(1000);
+ }
+
+ @Test
+ public void peekRefCountInfoTest() throws Exception {
+ ReferenceCountHelperImpl rchi = prepareInstance();
+ List<RefCountChangeInfo> expectedResult = Collections.emptyList();
+ when(rchi.peekRefCountInfo((long) 1000)).thenReturn(expectedResult);
+ List<RefCountChangeInfo> l = ReferenceCountHelper.peekRefCountInfo(1000);
+ assertEquals(l, expectedResult);
+ verify(rchi).peekRefCountInfo(1000);
+ }
+}
\ No newline at end of file