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