You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by kl...@apache.org on 2015/12/14 19:07:05 UTC

[32/48] incubator-geode git commit: GEODE-654: Changes LIFO queue to remove touched entry

GEODE-654: Changes LIFO queue to remove touched entry

Removes any entry that has been touched while processing
the LIFO queue. Prevents issue when eviction gets stuck
during startup and GII and an entry can not be removed.


Project: http://git-wip-us.apache.org/repos/asf/incubator-geode/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-geode/commit/f7670e16
Tree: http://git-wip-us.apache.org/repos/asf/incubator-geode/tree/f7670e16
Diff: http://git-wip-us.apache.org/repos/asf/incubator-geode/diff/f7670e16

Branch: refs/heads/feature/GEODE-217
Commit: f7670e1688a95a026a0376724bfe2277cb16eb94
Parents: fe29594
Author: Vince Ford <vf...@apache.org>
Authored: Fri Dec 11 11:30:35 2015 -0800
Committer: Vince Ford <vf...@apache.org>
Committed: Fri Dec 11 16:30:36 2015 -0800

----------------------------------------------------------------------
 .../internal/cache/lru/NewLIFOClockHand.java    |  78 ++++++++----
 .../internal/cache/lru/NewLRUClockHand.java     |  14 ++-
 ...victionAlgoMemoryEnabledRegionJUnitTest.java | 119 +++++++++++++++++++
 3 files changed, 185 insertions(+), 26 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/f7670e16/gemfire-core/src/main/java/com/gemstone/gemfire/internal/cache/lru/NewLIFOClockHand.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/internal/cache/lru/NewLIFOClockHand.java b/gemfire-core/src/main/java/com/gemstone/gemfire/internal/cache/lru/NewLIFOClockHand.java
index eac00c4..2ebc7a0 100755
--- a/gemfire-core/src/main/java/com/gemstone/gemfire/internal/cache/lru/NewLIFOClockHand.java
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/internal/cache/lru/NewLIFOClockHand.java
@@ -18,6 +18,7 @@ package com.gemstone.gemfire.internal.cache.lru;
 
 import com.gemstone.gemfire.cache.Region;
 import com.gemstone.gemfire.internal.cache.InternalRegionArguments;
+import com.gemstone.gemfire.internal.cache.AbstractRegionEntry;
 
 /**
  * NewLIFOClockHand holds the behavior for LIFO logic , Overwriting
@@ -39,30 +40,59 @@ public class NewLIFOClockHand extends NewLRUClockHand {
       ,NewLRUClockHand oldList){
     super(region,ccHelper,oldList);
   }
+  
+    /* Fetch the tail member which should be the last added value and remove it
+     * from the list
+     */
+    protected LRUClockNode getTailEntry() {
+        LRUClockNode aNode = null;
+        synchronized (this.lock) {
+            aNode = this.tail.prevLRUNode();
+            if (aNode == this.head) {
+                return null; //end of lru list
+            }
+            //remove entry from list
+            LRUClockNode prev = aNode.prevLRUNode();
+            prev.setNextLRUNode(this.tail);
+            this.tail.setPrevLRUNode(prev);
+            aNode.setNextLRUNode(null);
+            aNode.setPrevLRUNode(null);
+            super.size--;
+        }
+        return aNode;
+    }
 
-  /*
-   *  return the Entry that is considered most recently used
-   */
-  @Override
-   public LRUClockNode getLRUEntry() { // new getLIFOEntry
-    LRUClockNode aNode = null;
-    synchronized (this.lock) {
-      aNode = this.tail.prevLRUNode();
-      if(aNode == this.head) {
-        return null;
-      }
-      //TODO - Dan 9/23/09 We should probably
-      //do something like this to change the tail pointer.
-      //But this code wasn't changing the tail before
-      //I made this a doubly linked list, and I don't
-      //want to change it on this branch.
-//      LRUClockNode prev = aNode.prevLRUNode();
-//      prev.setNextLRUNode(this.tail);
-//      aNode.setNextLRUNode(null);
-//      aNode.setPrevLRUNode(null);
+    /*
+     *  return the Entry that is considered most recently used and available 
+     * to be evicted to overflow
+     */
+    @Override
+    public LRUClockNode getLRUEntry() {
+        long numEvals = 0;
+        LRUClockNode aNode = null;
+        //search for entry to return from list
+        for (;;) {
+            aNode = getTailEntry();
+            //end of Lifo list stop searching
+            if (aNode == null) {
+                break;
+            }
+            numEvals++;
+            synchronized (aNode) {
+                //look for another entry if in transaction
+		boolean inUseByTransaction = false;
+                if (aNode instanceof AbstractRegionEntry) {
+                    if (((AbstractRegionEntry) aNode).isInUseByTransaction()) {
+                       inUseByTransaction=true; 
+                    }
+                }
+                //if entry NOT used by transaction and NOT evicted return entry
+                if (!inUseByTransaction && !aNode.testEvicted()) {
+                    break;
+                }
+            }
+        }
+        this.stats().incEvaluations(numEvals);
+        return aNode;
     }
-    /* no need to update stats here as when this function finished executing 
-       next few calls update stats */
-    return aNode.testEvicted()? null:aNode;
-  }
 }

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/f7670e16/gemfire-core/src/main/java/com/gemstone/gemfire/internal/cache/lru/NewLRUClockHand.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/internal/cache/lru/NewLRUClockHand.java b/gemfire-core/src/main/java/com/gemstone/gemfire/internal/cache/lru/NewLRUClockHand.java
index b16cd91..59245f8 100755
--- a/gemfire-core/src/main/java/com/gemstone/gemfire/internal/cache/lru/NewLRUClockHand.java
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/internal/cache/lru/NewLRUClockHand.java
@@ -55,7 +55,7 @@ public class NewLRUClockHand  {
   /**  Description of the Field */
   final private LRUStatistics stats;
   /** Counter for the size of the LRU list */
-  private int size = 0;
+  protected int size = 0;
   
 public static final boolean debug = Boolean.getBoolean("gemfire.verbose-lru-clock");
 
@@ -185,7 +185,7 @@ public NewLRUClockHand(Object region, EnableLRU ccHelper,
       
       aNode.setNextLRUNode(null);
       aNode.setPrevLRUNode(null);
-      this.size++;
+      this.size--;
       return aNode;
     }
   }
@@ -334,6 +334,7 @@ public NewLRUClockHand(Object region, EnableLRU ccHelper,
       prev.setNextLRUNode(next);
       entry.setNextLRUNode(null);
       entry.setPrevLRUNode(null);
+      this.size--;
     }
     return true;
   }
@@ -386,6 +387,15 @@ public NewLRUClockHand(Object region, EnableLRU ccHelper,
     this.size = 0;
   }
   
+    /**
+     * Get size of LRU queue
+     *
+     * @return size
+     */
+    public int size() {
+        return size;
+    }
+
   /** perform work of clear(), after subclass has properly synchronized */
 //  private void internalClear() {
 //    stats().resetCounter();

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/f7670e16/gemfire-core/src/test/java/com/gemstone/gemfire/internal/cache/LIFOEvictionAlgoMemoryEnabledRegionJUnitTest.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/internal/cache/LIFOEvictionAlgoMemoryEnabledRegionJUnitTest.java b/gemfire-core/src/test/java/com/gemstone/gemfire/internal/cache/LIFOEvictionAlgoMemoryEnabledRegionJUnitTest.java
index e33c6ac..c8ffd7c 100755
--- a/gemfire-core/src/test/java/com/gemstone/gemfire/internal/cache/LIFOEvictionAlgoMemoryEnabledRegionJUnitTest.java
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/internal/cache/LIFOEvictionAlgoMemoryEnabledRegionJUnitTest.java
@@ -46,6 +46,8 @@ import com.gemstone.gemfire.distributed.DistributedSystem;
 import com.gemstone.gemfire.internal.cache.lru.LRUStatistics;
 import com.gemstone.gemfire.internal.cache.lru.NewLRUClockHand;
 import com.gemstone.gemfire.test.junit.categories.IntegrationTest;
+import com.gemstone.gemfire.internal.cache.lru.LRUClockNode;
+import com.gemstone.gemfire.internal.cache.lru.EnableLRU;
 
 /**
  * This is a test verifies region is LIFO enabled by MEMORY verifies correct
@@ -305,6 +307,53 @@ public class LIFOEvictionAlgoMemoryEnabledRegionJUnitTest {
       fail("Test failed");
     }
   }
+  
+//Basic checks to validate lifo queue implementation works as expected
+    @Test
+    public void testLIFOQueue() {
+        try {
+            assertNotNull(cache);
+            Region rgn = cache.getRegion(Region.SEPARATOR + regionName);
+            assertNotNull(rgn);
+            //insert data
+            lifoClockHand.appendEntry(new TestLRUNode(1));
+            lifoClockHand.appendEntry(new TestLRUNode(2));
+            lifoClockHand.appendEntry(new TestLRUNode(3));
+            assertTrue(lifoClockHand.size() == 3);
+            //make sure data is removed in LIFO fashion
+            TestLRUNode tailValue = (TestLRUNode) lifoClockHand.getLRUEntry();
+            assertTrue("Value = " + tailValue.getValue(), tailValue.getValue() == 3);
+            assertTrue("LIFO Queue Size = " + lifoClockHand.size(), lifoClockHand.size() == 2);
+            tailValue = (TestLRUNode) lifoClockHand.getLRUEntry();
+            assertTrue("Value = " + tailValue.getValue(), tailValue.getValue() == 2);
+            assertTrue("LIFO Queue Size = " + lifoClockHand.size(), lifoClockHand.size() == 1);
+            tailValue = (TestLRUNode) lifoClockHand.getLRUEntry();
+            assertTrue("Value = " + tailValue.getValue(), tailValue.getValue() == 1);
+            assertTrue("LIFO Queue Size = " + lifoClockHand.size(), lifoClockHand.size() == 0);
+            tailValue = (TestLRUNode) lifoClockHand.getLRUEntry();
+            assertTrue("No Value - null", tailValue == null);
+            assertTrue("LIFO Queue Size = " + lifoClockHand.size(), lifoClockHand.size() == 0);
+            //check that entries not available or already evicted are skipped and removed
+            TestLRUNode testlrunode = new TestLRUNode(1);
+            lifoClockHand.appendEntry(testlrunode);
+            testlrunode = new TestLRUNode(2);
+            testlrunode.setEvicted();
+            lifoClockHand.appendEntry(testlrunode);
+            testlrunode = new TestLRUNode(3);
+            testlrunode.setEvicted();
+            lifoClockHand.appendEntry(testlrunode);
+            tailValue = (TestLRUNode) lifoClockHand.getLRUEntry();
+            assertTrue("Value = " + tailValue.getValue(), tailValue.getValue() == 1);
+            assertTrue("LIFO Queue Size = " + lifoClockHand.size(), lifoClockHand.size() == 0);
+            tailValue = (TestLRUNode) lifoClockHand.getLRUEntry();
+            assertTrue("No Value - null", tailValue == null);
+            assertTrue("LIFO Queue Size = " + lifoClockHand.size(), lifoClockHand.size() == 0);
+            //TODO : need tests for data still part of transaction 
+        } catch (Exception ex) {
+            ex.printStackTrace();
+            fail(ex.getMessage());
+        }
+    }
 
   
   // purpose to create object ,size of byteArraySize 
@@ -315,3 +364,73 @@ public class LIFOEvictionAlgoMemoryEnabledRegionJUnitTest {
   }
 }
 
+//test class for validating LIFO queue
+class TestLRUNode implements LRUClockNode{
+  
+    LRUClockNode next=null;
+    LRUClockNode prev=null;
+    boolean evicted=false;
+    boolean recentlyUsed=false;
+    int value=0;
+    
+  public TestLRUNode(int value){
+      this.value=value;
+  }
+  
+  public int getValue(){ 
+      return value;
+  }
+  
+  public void setNextLRUNode( LRUClockNode next ){
+      this.next=next;
+  }
+  
+  public void setPrevLRUNode( LRUClockNode prev ){
+      this.prev=prev;
+  }
+  
+  public LRUClockNode nextLRUNode(){
+      return next;
+  }
+  
+  public LRUClockNode prevLRUNode(){
+      return prev;
+  }
+
+  public int updateEntrySize(EnableLRU ccHelper){
+      return 0;
+  }
+ 
+  public int updateEntrySize(EnableLRU ccHelper, Object value){
+      return 0;
+  }
+  
+  public int getEntrySize(){
+      return 0;
+  }
+  
+  public boolean testRecentlyUsed(){
+      return recentlyUsed;
+  }
+  
+  public void setRecentlyUsed(){
+      recentlyUsed=true;
+  }
+  
+  public void unsetRecentlyUsed(){
+      recentlyUsed=false;
+  }
+  
+  public void setEvicted(){
+      evicted=true;
+  }
+  
+  public void unsetEvicted(){
+      evicted=false;
+  }
+  
+  public boolean testEvicted(){
+      return evicted;
+  } 
+}
+