You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by kl...@apache.org on 2016/03/04 18:30:17 UTC

[05/14] incubator-geode git commit: Fix for GEODE-106 Invalidate operation fails with IndexMaintenanceException with underlying java.lang.ArrayIndexOutOfBoundsException.

Fix for GEODE-106 Invalidate operation fails with IndexMaintenanceException with underlying java.lang.ArrayIndexOutOfBoundsException.


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

Branch: refs/heads/feature/GEODE-949-2
Commit: 3996940954e6099fb927c1703a2c085760c4899a
Parents: c18f515
Author: Anil <ag...@pivotal.io>
Authored: Wed Feb 24 17:13:04 2016 -0800
Committer: Anil <ag...@pivotal.io>
Committed: Tue Mar 1 16:13:13 2016 -0800

----------------------------------------------------------------------
 .../query/internal/index/IndexElemArray.java    | 34 +++++-----
 .../internal/index/IndexElemArrayJUnitTest.java | 66 +++++++++++++++++---
 2 files changed, 74 insertions(+), 26 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/39969409/geode-core/src/main/java/com/gemstone/gemfire/cache/query/internal/index/IndexElemArray.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/com/gemstone/gemfire/cache/query/internal/index/IndexElemArray.java b/geode-core/src/main/java/com/gemstone/gemfire/cache/query/internal/index/IndexElemArray.java
index de694a4..7fdce2d 100644
--- a/geode-core/src/main/java/com/gemstone/gemfire/cache/query/internal/index/IndexElemArray.java
+++ b/geode-core/src/main/java/com/gemstone/gemfire/cache/query/internal/index/IndexElemArray.java
@@ -199,18 +199,20 @@ public class IndexElemArray implements Iterable, Collection {
    * @return <tt>true</tt> if this list contained the specified element
    */
   public boolean remove(Object o) {
-    if (o == null) {
-      for (int index = 0; index < size; index++)
-        if (elementData[index] == null) {
-          fastRemove(index);
-          return true;
-        }
-    } else {
-      for (int index = 0; index < size; index++)
-        if (o.equals(elementData[index])) {
-          fastRemove(index);
-          return true;
-        }
+    synchronized (lock) {
+      if (o == null) {
+        for (int index = 0; index < size; index++)
+          if (elementData[index] == null) {
+            fastRemove(index);
+            return true;
+          }
+      } else {
+        for (int index = 0; index < size; index++)
+          if (o.equals(elementData[index])) {
+            fastRemove(index);
+            return true;
+          }
+      }
     }
     return false;
   }
@@ -224,13 +226,11 @@ public class IndexElemArray implements Iterable, Collection {
     Object[] newArray = new Object[len - 1];
     System.arraycopy(elementData, 0, newArray, 0, index);
     int numMoved = len - index - 1;
-    if (numMoved > 0)
+    if (numMoved > 0) {
       System.arraycopy(elementData, index + 1, newArray, index, numMoved);
-
-    synchronized (lock) {
-      elementData = newArray;
-      --size;
     }
+    elementData = newArray;
+    --size;
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/39969409/geode-core/src/test/java/com/gemstone/gemfire/cache/query/internal/index/IndexElemArrayJUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/com/gemstone/gemfire/cache/query/internal/index/IndexElemArrayJUnitTest.java b/geode-core/src/test/java/com/gemstone/gemfire/cache/query/internal/index/IndexElemArrayJUnitTest.java
index 8c51264..91dbf7b 100644
--- a/geode-core/src/test/java/com/gemstone/gemfire/cache/query/internal/index/IndexElemArrayJUnitTest.java
+++ b/geode-core/src/test/java/com/gemstone/gemfire/cache/query/internal/index/IndexElemArrayJUnitTest.java
@@ -19,36 +19,37 @@ package com.gemstone.gemfire.cache.query.internal.index;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotSame;
 import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Iterator;
+import java.util.Random;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.stream.IntStream;
 
 import org.junit.After;
 import org.junit.Test;
 import org.junit.experimental.categories.Category;
 
+import com.gemstone.gemfire.cache.query.MultithreadedTester;
 import com.gemstone.gemfire.test.junit.categories.UnitTest;
 
 @Category(UnitTest.class)
 public class IndexElemArrayJUnitTest {
   
-  private IndexElemArray list;
+  private IndexElemArray list = new IndexElemArray(7);
 
   @After
   public void tearDown() {
-    System.clearProperty("index_elemarray_size");
+    //System.clearProperty("index_elemarray_size");
   }
   
   @Test
   public void testFunctionality() throws Exception {
-    // test disabled due to frequent failures that indicate that the product
-    // is malfunctioning.  See internal ticket #52285
-    if (true) {
-      return;
-    }
-    System.setProperty("index_elemarray_size", "7");
-    list = new IndexElemArray();
+    list.clear();
     boundaryCondition();
     add();
     clearAndAdd();
@@ -62,6 +63,52 @@ public class IndexElemArrayJUnitTest {
     clearAndAdd();
   }
 
+  @Test
+  /**
+   * This tests concurrent modification of IndexElemArray and to make 
+   * sure elementData and size are updated atomically. Ticket# GEODE-106.   
+   */
+  public void testFunctionalityUsingMultiThread() throws Exception {
+    list.clear();
+    Collection<Callable> callables = new ConcurrentLinkedQueue<>();    
+    IntStream.range(0, 1000).parallel().forEach(i -> {
+      callables.add(() -> {
+        if (i%3 == 0) {
+          return add(Integer.valueOf(new Random().nextInt(4)));
+        } else if (i%3 == 1) {
+          return remove(Integer.valueOf(new Random().nextInt(4)));
+        } else {
+          return iterateList();
+        }
+      });
+    });
+
+    Collection<Object> results = MultithreadedTester.runMultithreaded(callables);
+    results.forEach(result -> {
+      // There should not be any Exception here. 
+      // E.g. ArrayIndexOutOfBoundsException when multiple threads are acting.
+      assertTrue(result.getClass().getName() + " was not an expected result", result instanceof Integer);
+    });
+  }
+  
+  private Integer add(Integer i) {
+    list.add(i);
+    return i;
+  }
+  
+  private Integer remove(Integer i) {
+    list.remove(i);
+    return i;
+  }
+  
+  private Integer iterateList() {    
+    Iterator iter = list.iterator();
+    if (iter.hasNext()){ 
+      iter.next(); 
+    }
+    return Integer.valueOf(list.size());
+  }
+  
   private void add() {
     Object objBefore = list.getElementData();
     insert(7);
@@ -134,4 +181,5 @@ public class IndexElemArrayJUnitTest {
       // ok
     }
   }
+  
 }