/* * Copyright 2007-2010 Sun Microsystems, Inc. * * This file is part of Project Darkstar Server. * * Project Darkstar Server is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation and * distributed hereunder to you. * * Project Darkstar Server is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * -- */ package com.sun.sgs.test.app.util; import com.sun.sgs.app.ManagedObject; import com.sun.sgs.app.ObjectNotFoundException; import com.sun.sgs.app.util.ScalableHashMap; import com.sun.sgs.app.util.ManagedSerializable; import com.sun.sgs.auth.Identity; import static com.sun.sgs.impl.sharedutil.Objects.uncheckedCast; import com.sun.sgs.kernel.TransactionScheduler; import com.sun.sgs.service.DataService; import com.sun.sgs.test.util.SgsTestNode; import com.sun.sgs.test.util.TestAbstractKernelRunnable; import static com.sun.sgs.test.util.UtilReflection.getConstructor; import static com.sun.sgs.test.util.UtilReflection.getMethod; import com.sun.sgs.tools.test.FilteredNameRunner; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map.Entry; import java.util.Map; import java.util.NoSuchElementException; import java.util.Properties; import java.util.Random; import java.util.Set; import org.junit.AfterClass; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; /** * Test the {@link ScalableHashMap} class. */ @RunWith(FilteredNameRunner.class) public class TestScalableHashMap extends Assert { private static SgsTestNode serverNode; private static TransactionScheduler txnScheduler; private static Identity taskOwner; private static DataService dataService; /** A fixed random number generator for use in the test. */ private static final Random RANDOM = new Random(1337); /** The four argument constructor. */ private static final Constructor<ScalableHashMap> scalableHashMapConstructor = getConstructor( ScalableHashMap.class, int.class, int.class, int.class, int.class); /** The findMinDepthFor method. */ private static final Method findMinDepthFor = getMethod(ScalableHashMap.class, "findMinDepthFor", int.class); /** The getMinTreeDepth method. */ private static final Method getMinTreeDepth = getMethod(ScalableHashMap.class, "getMinTreeDepth"); /** The getMaxTreeDepth method. */ private static final Method getMaxTreeDepth = getMethod(ScalableHashMap.class, "getMaxTreeDepth"); /** The getAvgTreeDepth method. */ private static final Method getAvgTreeDepth = getMethod(ScalableHashMap.class, "getAvgTreeDepth"); /** The checkLeafRefs method. */ private static final Method checkLeafRefs = getMethod(ScalableHashMap.class, "checkLeafRefs"); /** * Test management. */ @BeforeClass public static void setUpClass() throws Exception { serverNode = new SgsTestNode("TestScalableHashMap", null, createProps("TestScalableHashMap")); txnScheduler = serverNode.getSystemRegistry(). getComponent(TransactionScheduler.class); taskOwner = serverNode.getProxy().getCurrentOwner(); dataService = serverNode.getDataService(); } @AfterClass public static void tearDownClass() throws Exception { serverNode.shutdown(true); } /* * Test no arg constructor */ @Test public void testConstructorNoArg() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap test = new ScalableHashMap<Integer,Integer>(); assertEquals(6, getMaxTreeDepth(test)); assertEquals(6, getMaxTreeDepth(test)); dataService.setBinding("test", test); } }, taskOwner); txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap test = (ScalableHashMap) dataService.getBinding("test"); assertEquals(6, getMaxTreeDepth(test)); assertEquals(6, getMinTreeDepth(test)); } }, taskOwner); } /* * Test minimum concurrency constructor */ @Test public void testConstructorOneArgDepth() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap<Integer,Integer> test = new ScalableHashMap<Integer,Integer>(1); assertEquals(1, getMaxTreeDepth(test)); assertEquals(1, getMinTreeDepth(test)); } }, taskOwner); } @Test public void testConstructorOneArgDepth3() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap<Integer,Integer> test = new ScalableHashMap<Integer,Integer>(3); assertEquals(3, getMaxTreeDepth(test)); assertEquals(3, getMinTreeDepth(test)); } }, taskOwner); } @Test public void testConstructorOneArgDepth4() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap<Integer,Integer> test = new ScalableHashMap<Integer,Integer>(5); assertEquals(4, getMaxTreeDepth(test)); assertEquals(4, getMinTreeDepth(test)); } }, taskOwner); } @Test public void testConstructorOneArgWithZeroMaxConcurrencyException() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { try { new ScalableHashMap<Integer,Integer>(0); fail("Expected IllegalArgumentException"); } catch (IllegalArgumentException iae) { } } }, taskOwner); } /** This test reproduces the problem reported in sgs-server issue #160. */ @Test public void testConstructorOneArgHighConcurrency() throws Exception { for (final int concurrency : new int[] { 256, 1024 }) { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { Map<Integer, Integer> map = new ScalableHashMap<Integer,Integer>(256); map.keySet().iterator(); } }, taskOwner); } } // NOTE: we do not test the maximum concurrency in the // constructor, as this would take far too long to test (hours). /* * Test copy constructor */ @Test public void testCopyConstructor() throws Exception { final Map<Integer,Integer> control = new HashMap<Integer,Integer>(); txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { for (int i = 0; i < 32; i++) { control.put(i,i); } ScalableHashMap<Integer,Integer> test = new ScalableHashMap<Integer,Integer>(control); assertEquals(control, test); dataService.setBinding("test", test); } }, taskOwner); txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap test = (ScalableHashMap) dataService.getBinding("test"); assertEquals(control, test); } }, taskOwner); } @Test public void testNullCopyConstructor() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { try { new ScalableHashMap<Integer,Integer>(null); fail("Expected NullPointerException"); } catch (NullPointerException npe) { } } }, taskOwner); } /* * Test non-public constructor */ @Test public void testMultiParamConstructor() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { createScalableHashMap(Integer.class, Integer.class, 1, 32, 5); createScalableHashMap(Integer.class, Integer.class, 1, 32, 4); } }, taskOwner); } @Test public void testMultiParamConstructorBadMinConcurrency() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { try { createScalableHashMap(Integer.class, Integer.class, 0, 1, 5); fail("Expected IllegalArgumentException"); } catch(IllegalArgumentException iae) { } } }, taskOwner); } @Test public void testMultiParamConstructorBadSplitThreshold() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { try { createScalableHashMap(Integer.class, Integer.class, 1, 0, 5); fail("Expected IllegalArgumentException"); } catch (IllegalArgumentException iae) { } } }, taskOwner); } @Test public void testMultiParamConstructorBadDirectorySize() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { try { createScalableHashMap(Integer.class, Integer.class, 1, 32, -1); fail("Expected IllegalArgumentException"); } catch (IllegalArgumentException iae) { } } }, taskOwner); } /* * Test putAll */ @Test public void testPutAllMisc() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { Map<Integer,Integer> control = new HashMap<Integer,Integer>(); for (int i = 0; i < 32; i++) { control.put(i,i); } Map<Integer,Integer> test = new ScalableHashMap<Integer,Integer>(); test.putAll(control); assertEquals(control, test); } }, taskOwner); } @Test public void testPutAllNullArg() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { Map<Integer,Integer> test = new ScalableHashMap<Integer,Integer>(); try { test.putAll(null); fail("Expected NullPointerException"); } catch (NullPointerException e) { } } }, taskOwner); } @Test public void testPutAllNotSerializable() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { Map<Object,Object> test = new ScalableHashMap<Object,Object>(); Object nonSerializable = Thread.currentThread(); Map<Object,Object> other = new HashMap<Object,Object>(); other.put(nonSerializable, Boolean.TRUE); try { test.putAll(other); fail("Expected IllegalArgumentException"); } catch (IllegalArgumentException e) { } other.clear(); other.put(Boolean.TRUE, nonSerializable); try { test.putAll(other); fail("Expected IllegalArgumentException"); } catch (IllegalArgumentException e) { } } }, taskOwner); } @Test public void testPutAllNullItems() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { Map<Object,Object> test = new ScalableHashMap<Object,Object>(); Object nonSerializable = Thread.currentThread(); Map<Object,Object> control = new HashMap<Object,Object>(); test.put(0, null); control.put(0, null); test.put(null, 0); control.put(null, 0); assertEquals(test, control); } }, taskOwner); } /* * Test put */ @Test public void testPutMisc() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { Map<Integer,Foo> test = new ScalableHashMap<Integer,Foo>(); Foo result = test.put(1, new Foo(1)); assertEquals(null, result); result = test.put(1, new Foo(1)); assertEquals(new Foo(1), result); result = test.put(1, new Foo(37)); assertEquals(new Foo(1), result); } }, taskOwner); } @Test public void testPutNotSerializable() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { Map<Object,Object> test = new ScalableHashMap<Object,Object>(); Object nonSerializable = Thread.currentThread(); try { test.put(nonSerializable, Boolean.TRUE); fail("Expected IllegalArgumentException"); } catch (IllegalArgumentException e) { assertTrue(test.isEmpty()); } try { test.put(Boolean.TRUE, nonSerializable); fail("Expected IllegalArgumentException"); } catch (IllegalArgumentException e) { assertTrue(test.isEmpty()); } } }, taskOwner); } @SuppressWarnings("unchecked") @Test public void testPutOldValueNotFound() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap test = new ScalableHashMap(); dataService.setBinding("test", test); Bar bar = new Bar(1); dataService.setBinding("bar", bar); test.put(Boolean.TRUE, bar); } }, taskOwner); txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { dataService.removeObject(dataService.getBinding("bar")); ScalableHashMap test = (ScalableHashMap) dataService.getBinding("test"); try { test.put(Boolean.TRUE, Boolean.FALSE); fail("Expected ObjectNotFoundException"); } catch (ObjectNotFoundException e) { assertEquals(1, test.size()); } } }, taskOwner); txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap test = (ScalableHashMap) dataService.getBinding("test"); try { test.put(Boolean.TRUE, Boolean.FALSE); fail("Expected ObjectNotFoundException"); } catch (ObjectNotFoundException e) { assertEquals(1, test.size()); } } }, taskOwner); } @SuppressWarnings("unchecked") @Test public void testPutOldKeyNotFound() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap test = new ScalableHashMap(); dataService.setBinding("test", test); Bar bar = new Bar(1); dataService.setBinding("bar", bar); test.put(bar, Boolean.TRUE); } }, taskOwner); try { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { dataService.removeObject( dataService.getBinding("bar")); ScalableHashMap test = (ScalableHashMap) dataService.getBinding("test"); assertEquals(null, test.put(new Bar(1), Boolean.FALSE)); assertEquals(Boolean.FALSE, test.get(new Bar(1))); throw new RuntimeException("Intentional Abort"); } }, taskOwner); } catch (RuntimeException re) {} txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { dataService.removeObject(dataService.getBinding("bar")); ScalableHashMap test = (ScalableHashMap) dataService.getBinding("test"); } }, taskOwner); txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap test = (ScalableHashMap) dataService.getBinding("test"); assertEquals(null, test.put(new Bar(1), Boolean.FALSE)); assertEquals(Boolean.FALSE, test.get(new Bar(1))); } }, taskOwner); } @Test public void testPutNullKey() throws Exception { final Map<String,Integer> control = new HashMap<String,Integer>(); txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap<String,Integer> test = new ScalableHashMap<String,Integer>(16); test.put(null, 0); control.put(null, 0); assertEquals(control, test); dataService.setBinding("test", test); } }, taskOwner); txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { assertEquals(control, dataService.getBinding("test")); } }, taskOwner); } @Test public void testPutNullValue() throws Exception { final Map<Integer,String> control = new HashMap<Integer,String>(); txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap<Integer,String> test = new ScalableHashMap<Integer,String>(16); test.put(0, null); control.put(0, null); assertEquals(control, test); dataService.setBinding("test", test); } }, taskOwner); txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { assertEquals(control, dataService.getBinding("test")); } }, taskOwner); } /* * Test get */ @Test public void testGetMisc() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { Map<Integer,Foo> test = new ScalableHashMap<Integer,Foo>(); assertEquals(null, test.get(1)); test.put(1, new Foo(1)); assertEquals(new Foo(1), test.get(1)); assertEquals(null, test.get(new Foo(1))); assertEquals(null, test.get(2)); } }, taskOwner); } @SuppressWarnings("unchecked") @Test public void testGetValueNotFound() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap test = new ScalableHashMap(); dataService.setBinding("test", test); Bar bar = new Bar(1); dataService.setBinding("bar", bar); test.put(Boolean.TRUE, bar); } }, taskOwner); txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { dataService.removeObject(dataService.getBinding("bar")); ScalableHashMap test = (ScalableHashMap) dataService.getBinding("test"); try { test.get(Boolean.TRUE); fail("Expected ObjectNotFoundException"); } catch (ObjectNotFoundException e) { assertEquals(1, test.size()); } } }, taskOwner); txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap test = (ScalableHashMap) dataService.getBinding("test"); try { test.get(Boolean.TRUE); fail("Expected ObjectNotFoundException"); } catch (ObjectNotFoundException e) { assertEquals(1, test.size()); } } }, taskOwner); } @SuppressWarnings("unchecked") @Test public void testGetKeyNotFound() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap test = new ScalableHashMap(); dataService.setBinding("test", test); Bar bar = new Bar(1); dataService.setBinding("bar", bar); test.put(bar, Boolean.TRUE); } }, taskOwner); txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { dataService.removeObject(dataService.getBinding("bar")); ScalableHashMap test = (ScalableHashMap) dataService.getBinding("test"); assertEquals(null, test.get(new Bar(1))); } }, taskOwner); txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap test = (ScalableHashMap) dataService.getBinding("test"); assertEquals(null, test.get(new Bar(1))); } }, taskOwner); } @Test public void testGetNullKey() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap<String,Integer> test = new ScalableHashMap<String,Integer>(16); test.put(null, 0); assertEquals(new Integer(0), test.get(null)); dataService.setBinding("test", test); } }, taskOwner); txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { assertEquals( new Integer(0), ((Map) dataService.getBinding("test")).get(null)); } }, taskOwner); } @Test public void testGetNullValue() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap<Integer,String> test = new ScalableHashMap<Integer,String>(16); test.put(0, null); assertEquals(null, test.get(0)); dataService.setBinding("test", test); } }, taskOwner); txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { assertEquals(null, ((Map) dataService.getBinding( "test")).get(0)); } }, taskOwner); } /* * Test containsKey */ @Test public void testContainsKeyMisc() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { Map<Integer,Foo> test = new ScalableHashMap<Integer,Foo>(); assertFalse(test.containsKey(1)); test.put(1, new Foo(1)); assertTrue(test.containsKey(1)); assertFalse(test.containsKey(new Foo(1))); assertFalse(test.containsKey(2)); } }, taskOwner); } @Test public void testContainsKeyNull() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap<String,Integer> test = new ScalableHashMap<String,Integer>(16); test.put(null, 0); assertTrue(test.containsKey(null)); dataService.setBinding("test", test); } }, taskOwner); txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { assertTrue(((Map) dataService.getBinding( "test")).containsKey(null)); } }, taskOwner); } @Test public void testContainsKeyNullOnEmptyMap() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap<String,Integer> test = new ScalableHashMap<String,Integer>(16); assertFalse(test.containsKey(null)); dataService.setBinding("test", test); } }, taskOwner); txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { assertFalse(((Map) dataService.getBinding( "test")).containsKey(null)); } }, taskOwner); } @SuppressWarnings("unchecked") @Test public void testContainsKeyKeyNotFound() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap test = new ScalableHashMap(16); dataService.setBinding("test", test); Bar bar = new Bar(1); dataService.setBinding("bar", bar); test.put(bar, 1); test.put(new Bar(2), 2); } }, taskOwner); txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { dataService.removeObject(dataService.getBinding("bar")); ScalableHashMap test = (ScalableHashMap) dataService.getBinding("test"); assertFalse(test.containsKey(new Bar(1))); assertEquals(2, test.size()); } }, taskOwner); txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap test = (ScalableHashMap) dataService.getBinding("test"); assertFalse(test.containsKey(new Bar(1))); assertEquals(2, test.size()); } }, taskOwner); } @SuppressWarnings("unchecked") @Test public void testContainsKeyValueNotFound() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap test = new ScalableHashMap(16); dataService.setBinding("test", test); Bar bar = new Bar(1); dataService.setBinding("bar", bar); test.put(1, bar); test.put(2, new Bar(2)); } }, taskOwner); txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { dataService.removeObject(dataService.getBinding("bar")); ScalableHashMap test = (ScalableHashMap) dataService.getBinding("test"); assertTrue(test.containsKey(1)); assertEquals(2, test.size()); } }, taskOwner); txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap test = (ScalableHashMap) dataService.getBinding("test"); assertTrue(test.containsKey(1)); assertEquals(2, test.size()); } }, taskOwner); } @Test public void testContainsKeyOnSplitTree() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { Map<Integer,Integer> test = new ScalableHashMap<Integer,Integer>(16); Map<Integer,Integer> control = new HashMap<Integer,Integer>(); int[] inputs = new int[50]; for (int i = 0; i < inputs.length; i++) { int j = RANDOM.nextInt(); inputs[i] = j; test.put(j,-j); } for (int i = 0; i < inputs.length; i++) { assertTrue(test.containsKey(inputs[i])); } } }, taskOwner); } /* * Test containsValue */ @Test public void testContainsValueMisc() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { Map<Integer,Foo> test = new ScalableHashMap<Integer,Foo>(); assertFalse(test.containsValue(new Foo(1))); test.put(1, new Foo(1)); assertTrue(test.containsValue(new Foo(1))); assertFalse(test.containsValue(1)); assertFalse(test.containsValue(new Foo(2))); } }, taskOwner); } @SuppressWarnings("unchecked") @Test public void testContainsValueNull() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap<Integer,Integer> test = new ScalableHashMap<Integer,Integer>(); test.put(0, null); dataService.setBinding("test", test); assertTrue(test.containsValue(null)); } }, taskOwner); txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap<Integer,Integer> test = uncheckedCast(dataService.getBinding("test")); assertTrue(test.containsValue(null)); } }, taskOwner); } @SuppressWarnings("unchecked") @Test public void testContainsValueNullEmptyMap() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap<Integer,Integer> test = new ScalableHashMap<Integer,Integer>(); dataService.setBinding("test", test); assertFalse(test.containsValue(null)); } }, taskOwner); txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap<Integer,Integer> test = uncheckedCast(dataService.getBinding("test")); assertFalse(test.containsValue(null)); } }, taskOwner); } @SuppressWarnings("unchecked") @Test public void testContainsValueValueNotFound() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap test = new ScalableHashMap(); dataService.setBinding("test", test); Bar bar = new Bar(1); dataService.setBinding("bar", bar); test.put(1, bar); test.put(2, new Bar(2)); } }, taskOwner); txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { dataService.removeObject(dataService.getBinding("bar")); ScalableHashMap test = (ScalableHashMap) dataService.getBinding("test"); assertFalse(test.containsValue(new Bar(1))); assertEquals(2, test.size()); } }, taskOwner); txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap test = (ScalableHashMap) dataService.getBinding("test"); assertFalse(test.containsValue(new Bar(1))); assertEquals(2, test.size()); } }, taskOwner); } @SuppressWarnings("unchecked") @Test public void testContainsValueKeyNotFound() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap test = new ScalableHashMap(); dataService.setBinding("test", test); Bar bar = new Bar(1); dataService.setBinding("bar", bar); test.put(bar, 1); test.put(new Bar(2), 2); } }, taskOwner); txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { dataService.removeObject(dataService.getBinding("bar")); ScalableHashMap test = (ScalableHashMap) dataService.getBinding("test"); assertTrue(test.containsValue(1)); assertEquals(2, test.size()); } }, taskOwner); txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap test = (ScalableHashMap) dataService.getBinding("test"); assertTrue(test.containsValue(1)); assertEquals(2, test.size()); } }, taskOwner); } @Test public void testContainsValueNullOnSplitMap() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { Map<Integer,Integer> test = new ScalableHashMap<Integer,Integer>(16); test.put(0, null); assertTrue(test.containsValue(null)); } }, taskOwner); } @Test public void testContainsValue() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { Map<Integer,Integer> test = new ScalableHashMap<Integer,Integer>(); Map<Integer,Integer> control = new HashMap<Integer,Integer>(); int[] inputs = new int[50]; for (int i = 0; i < inputs.length; i++) { int j = RANDOM.nextInt(); inputs[i] = j; test.put(j,-j); } for (int i = 0; i < inputs.length; i++) { assertTrue(test.containsValue(-inputs[i])); } } }, taskOwner); } @Test public void testContainsValueOnSplitTree() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { Map<Integer,Integer> test = new ScalableHashMap<Integer,Integer>(16); Map<Integer,Integer> control = new HashMap<Integer,Integer>(); int[] inputs = new int[50]; for (int i = 0; i < inputs.length; i++) { int j = RANDOM.nextInt(); inputs[i] = j; test.put(j,-j); } for (int i = 0; i < inputs.length; i++) { assertTrue(test.containsValue(-inputs[i])); } } }, taskOwner); } /* * Test values */ @SuppressWarnings("unchecked") @Test public void testValues() throws Exception { final Map<Integer,Integer> control = new HashMap<Integer,Integer>(); final Collection<Integer> controlValues = control.values(); txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { Map<Integer,Integer> test = new ScalableHashMap<Integer,Integer>(); Collection<Integer> values = test.values(); assertTrue(values.isEmpty()); assertIteratorDone(values.iterator()); for (int i = 0; i < 50; i++) { int j = RANDOM.nextInt(); test.put(j,-j); control.put(j,-j); } assertEquals(50, values.size()); assertTrue(controlValues.containsAll(values)); assertIteratorContains(controlValues, values.iterator()); dataService.setBinding("values", new ManagedSerializable(values)); } }, taskOwner); txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ManagedSerializable<Collection<Integer>> ms = uncheckedCast(dataService.getBinding("values")); Collection<Integer> values = ms.get(); assertEquals(50, values.size()); assertTrue(controlValues.containsAll(values)); assertIteratorContains(controlValues, values.iterator()); } }, taskOwner); } @Test public void testValuesOnSplitTree() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { Map<Integer,Integer> test = new ScalableHashMap<Integer,Integer>(16); Collection<Integer> control = new ArrayList<Integer>(50); int[] inputs = new int[50]; for (int i = 0; i < inputs.length; i++) { int j = RANDOM.nextInt(); inputs[i] = j; test.put(j,-j); control.add(-j); } assertTrue(control.containsAll(test.values())); } }, taskOwner); } /* * Test keySet */ @SuppressWarnings("unchecked") @Test public void testKeySet() throws Exception { final Map control = new HashMap(); final Set controlKeys = control.keySet(); txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { Map test = new ScalableHashMap(); Set keys = test.keySet(); assertEquals(controlKeys, keys); assertIteratorDone(keys.iterator()); assertEquals(controlKeys.hashCode(), keys.hashCode()); for (int i = 0; i < 50; i++) { int j = RANDOM.nextInt(); test.put(j,-j); control.put(j,-j); } assertEquals(controlKeys, keys); assertIteratorContains(controlKeys, keys.iterator()); assertEquals(controlKeys.hashCode(), keys.hashCode()); dataService.setBinding("keys", new ManagedSerializable(keys)); } }, taskOwner); txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ManagedSerializable<Set> ms = uncheckedCast(dataService.getBinding("keys")); Set keys = ms.get(); assertEquals(controlKeys, keys); assertIteratorContains(controlKeys, keys.iterator()); assertEquals(controlKeys.hashCode(), keys.hashCode()); } }, taskOwner); } /* * Test entrySet */ @SuppressWarnings("unchecked") @Test public void testEntrySet() throws Exception { final Map control = new HashMap(); final Set controlEntries = control.entrySet(); txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { Map test = new ScalableHashMap(); Set entries = test.entrySet(); assertEquals(controlEntries, entries); assertIteratorDone(entries.iterator()); assertEquals(controlEntries.hashCode(), entries.hashCode()); for (int i = 0; i < 50; i++) { int j = RANDOM.nextInt(); test.put(j,-j); control.put(j,-j); } assertEquals(controlEntries, entries); assertIteratorContains(controlEntries, entries.iterator()); assertEquals(controlEntries.hashCode(), entries.hashCode()); dataService.setBinding("entries", new ManagedSerializable(entries)); } }, taskOwner); txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ManagedSerializable<Set> ms = uncheckedCast(dataService.getBinding("entries")); Set entries = ms.get(); assertEquals(controlEntries, entries); assertEquals(controlEntries.hashCode(), entries.hashCode()); } }, taskOwner); } /* * Test equals and hashCode */ @SuppressWarnings("unchecked") @Test public void testEquals() throws Exception { final Map control = new HashMap(); txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap test = new ScalableHashMap(); assertFalse(test.equals(null)); assertFalse(test.equals(1)); assertTrue(test.equals(control)); assertEquals(test.hashCode(), control.hashCode()); for (int i = 0; i < 50; i++) { int j = RANDOM.nextInt(); test.put(j,-j); control.put(j,-j); } assertTrue(test.equals(control)); assertEquals(test.hashCode(), control.hashCode()); dataService.setBinding("test", test); } }, taskOwner); txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap test = (ScalableHashMap) dataService.getBinding("test"); assertTrue(test.equals(control)); assertEquals(test.hashCode(), control.hashCode()); } }, taskOwner); } /* * Test toString */ @Test public void testToString() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap<Integer,Integer> test = new ScalableHashMap<Integer,Integer>(); assertEquals("{}", test.toString()); test.put(1, 2); assertEquals("{1=2}", test.toString()); } }, taskOwner); } /* * Test remove */ @Test public void testRemoveMisc() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { Map<Integer,Foo> test = new ScalableHashMap<Integer,Foo>(); assertEquals(null, test.remove(1)); test.put(1, new Foo(1)); assertEquals(null, test.remove(2)); assertEquals(null, test.remove(new Foo(1))); assertEquals(new Foo(1), test.remove(1)); assertTrue(test.isEmpty()); assertEquals(null, test.remove(1)); } }, taskOwner); } @Test public void testRemoveNullKey() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { Map<String,Integer> test = new ScalableHashMap<String,Integer>(16); Map<String,Integer> control = new HashMap<String,Integer>(); test.put(null, 0); control.put(null, 0); assertEquals(control, test); test.remove(null); control.remove(null); assertEquals(control, test); } }, taskOwner); } @SuppressWarnings("unchecked") @Test public void testRemoveValueNotFound() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap test = new ScalableHashMap(); dataService.setBinding("test", test); Bar bar = new Bar(1); dataService.setBinding("bar", bar); test.put(1, bar); } }, taskOwner); txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { dataService.removeObject(dataService.getBinding("bar")); ScalableHashMap test = (ScalableHashMap) dataService.getBinding("test"); try { test.remove(1); fail("Expected ObjectNotFoundException"); } catch (ObjectNotFoundException e) { } assertEquals(null, test.remove(2)); } }, taskOwner); txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap test = (ScalableHashMap) dataService.getBinding("test"); try { test.remove(1); fail("Expected ObjectNotFoundException"); } catch (ObjectNotFoundException e) { } assertEquals(null, test.remove(2)); } }, taskOwner); } @SuppressWarnings("unchecked") @Test public void testRemoveKeyNotFound() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap test = new ScalableHashMap(); dataService.setBinding("test", test); Bar bar = new Bar(1); dataService.setBinding("bar", bar); test.put(bar, 1); } }, taskOwner); txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { dataService.removeObject(dataService.getBinding("bar")); ScalableHashMap test = (ScalableHashMap) dataService.getBinding("test"); assertEquals(null, test.remove(new Bar(1))); assertEquals(null, test.remove(1)); assertEquals(null, test.remove(new Bar(2))); } }, taskOwner); txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap test = (ScalableHashMap) dataService.getBinding("test"); assertEquals(null, test.remove(new Bar(1))); assertEquals(null, test.remove(1)); assertEquals(null, test.remove(new Bar(2))); } }, taskOwner); } /* * Test clear */ @Test public void testClear() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { Map<Integer,Integer> test = new ScalableHashMap<Integer,Integer>(16); Map<Integer,Integer> control = new HashMap<Integer,Integer>(); int[] inputs = new int[50]; for (int i = 0; i < inputs.length; i++) { int j = RANDOM.nextInt(); inputs[i] = j; test.put(j,j); control.put(j,j); } assertEquals(control, test); DoneRemoving.init(); test.clear(); control.clear(); /* * XXX: Test that clear does not change the minimum depth. * -tjb@sun.com (10/04/2007) */ assertEquals(control, test); } }, taskOwner); DoneRemoving.await(1); } @SuppressWarnings("unchecked") @Test public void testMultipleClearOperations() throws Exception { final Map<Integer,Integer> control = new HashMap<Integer,Integer>(); txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap<Integer,Integer> test = new ScalableHashMap<Integer,Integer>(); DoneRemoving.init(); test.clear(); assertEquals(control, test); dataService.setBinding("test", test); } }, taskOwner); DoneRemoving.await(1); txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap<Integer,Integer> test = uncheckedCast(dataService.getBinding("test")); // add just a few elements for (int i = 0; i < 33; i++) { int j = RANDOM.nextInt(); test.put(j,j); } test.clear(); assertEquals(control, test); } }, taskOwner); DoneRemoving.await(1); txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap<Integer,Integer> test = uncheckedCast(dataService.getBinding("test")); // add just enough elements to force a split for (int i = 0; i < 1024; i++) { int j = RANDOM.nextInt(); test.put(j,j); } test.clear(); assertEquals(control, test); } }, taskOwner); DoneRemoving.await(1); } /* * Miscellaneous tests */ @Test public void testPutAndGetOnSingleLeaf() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { Map<Integer,Integer> test = new ScalableHashMap<Integer,Integer>(); Map<Integer,Integer> control = new HashMap<Integer,Integer>(); for (int count = 0; count < 64; ++count) { int i = RANDOM.nextInt(); test.put(i, i); test.put(~i, ~i); control.put(i,i); control.put(~i, ~i); assertEquals(control, test); } } }, taskOwner); } @Test public void testPutAndGetOnSplitTree() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { Map<Integer,Integer> test = new ScalableHashMap<Integer,Integer>(16); Map<Integer,Integer> control = new HashMap<Integer,Integer>(); for (int count = 0; count < 32; ++count) { int i = RANDOM.nextInt(); test.put(i, i); control.put(i,i); assertEquals(control, test); } } }, taskOwner); } @Test public void testPutAndRemoveSingleLeaf() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { Map<Integer,Integer> test = new ScalableHashMap<Integer,Integer>(); Map<Integer,Integer> control = new HashMap<Integer,Integer>(); for (int i = 0; i < 54; i++) { test.put(i, i); test.put(~i, ~i); control.put(i, i); control.put(~i, ~i); } for (int i = 0; i < 54; i += 2) { test.remove(i); control.remove(i); } assertEquals(control, test); } }, taskOwner); } @Test public void testPutAndRemoveLopsidedPositiveKeys() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap<Integer,Integer> test = new ScalableHashMap<Integer,Integer>(); Map<Integer,Integer> control = new HashMap<Integer,Integer>(); for (int i = 0; i < 128; i++) { test.put(i, i); control.put(i, i); } assertEquals(control, test); for (int i = 0; i < 128; i += 2) { test.remove(i); control.remove(i); } assertEquals(control, test); } }, taskOwner); } @Test public void testPutAndRemoveLopsidedNegativeKeys() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap<Integer,Integer> test = new ScalableHashMap<Integer,Integer>(); Map<Integer,Integer> control = new HashMap<Integer,Integer>(); for (int i = 0; i < 128; i++) { test.put(-i, i); control.put(-i, i); } assertEquals(control, test); for (int i = 0; i < 128; i += 2) { test.remove(-i); control.remove(-i); } assertEquals(control, test); } }, taskOwner); } @Test public void testPutAndRemoveDoublyLopsided() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap<Integer,Integer> test = new ScalableHashMap<Integer,Integer>(); Map<Integer,Integer> control = new HashMap<Integer,Integer>(); for (int i = 0; i < 96; i++) { test.put(i, i); test.put(-i, -i); control.put(i, i); control.put(-i, -i); } assertEquals(control, test); for (int i = 0; i < 127; i += 2) { assertEquals(control.remove(i), test.remove(i)); } assertEquals(control, test); } }, taskOwner); } @Test public void testPutAndRemoveHalfRandomKeys() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap<Integer,Integer> test = new ScalableHashMap<Integer,Integer>(); Map<Integer,Integer> control = new LinkedHashMap<Integer,Integer>(); int[] vals = new int[128]; for (int i = 0; i < 128; i++) { int j = (i < 64) ? -RANDOM.nextInt() : RANDOM.nextInt(); vals[i] = j; test.put(j, i); control.put(j, i); } assertEquals(control, test); for (int i = 0; i < 128; i += 2) { test.remove(vals[i]); control.remove(vals[i]); } assertEquals(control, test); } }, taskOwner); } @Test public void testPutAndRemoveHalfNegativeKeys() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap<Integer,Integer> test = new ScalableHashMap<Integer,Integer>(); Map<Integer,Integer> control = new LinkedHashMap<Integer,Integer>(); for (int i = 0; i < 128; i++) { test.put(-i, -i); control.put(-i, -i); } assertEquals(control, test); for (int i = 0; i < 128; i += 2) { test.remove(-i); control.remove(-i); } assertEquals(control, test); } }, taskOwner); } @Test public void testPutAndRemoveOnSplitTree0() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap<Integer,Integer> test = new ScalableHashMap<Integer,Integer>(); Map<Integer,Integer> control = new HashMap<Integer,Integer>(); int[] a = new int[12]; for (int i = 0; i < 12; i++) { int j = RANDOM.nextInt(); a[i] = j; test.put(j, i); control.put(j, i); } assertEquals(control, test); checkLeafRefs(test); for (int i = 0; i < 12; i += 2) { test.remove(a[i]); control.remove(a[i]); } for (int i = 0; i < 6; i += 2) { test.get(a[i]); } for (int i = 1; i < 6; i += 2) { test.get(a[i]); } assertEquals(control, test); for (Integer k : control.keySet()) { assertTrue(test.containsKey(k)); assertTrue(test.containsValue(control.get(k))); } for (Integer k : test.keySet()) { assertTrue(control.containsKey(k)); assertTrue(control.containsValue(test.get(k))); } assertEquals(control, test); checkLeafRefs(test); } }, taskOwner); } @Test public void testPutAndRemoveOnSplitTree() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap<Integer,Integer> test = new ScalableHashMap<Integer,Integer>(16); Map<Integer,Integer> control = new HashMap<Integer,Integer>(); for (int i = 0; i < 24; i++) { test.put(i, i); test.put(~i, ~i); control.put(i,i); control.put(~i, ~i); } for (int i = 0; i < 24; i += 2) { test.remove(i); control.remove(i); } assertEquals(control, test); checkLeafRefs(test); } }, taskOwner); } @Test public void testPutAndRemoveOnNoMergeTreeWithNoCollapse() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { Map<Integer,Integer> test = createScalableHashMap(Integer.class, Integer.class, 1, 8, 2); Map<Integer,Integer> control = new HashMap<Integer,Integer>(); int[] inputs = new int[1024]; for (int i = 0; i < inputs.length; i++) { int j = RANDOM.nextInt(); inputs[i] = j; test.put(j,j); control.put(j,j); } for (int i = 0; i < inputs.length; i += 2) { test.remove(inputs[i]); control.remove(inputs[i]); } assertEquals(control, test); } }, taskOwner); } @Test public void testPutAndRemoveOnNoMergeTreeWithCollapse() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { Map<Integer,Integer> test = createScalableHashMap(Integer.class, Integer.class, 1, 8, 4); Map<Integer,Integer> control = new HashMap<Integer,Integer>(); int[] inputs = new int[1024]; for (int i = 0; i < inputs.length; i++) { int j = RANDOM.nextInt(); inputs[i] = j; test.put(j,j); control.put(j,j); } for (int i = 0; i < inputs.length; i += 2) { test.remove(inputs[i]); control.remove(inputs[i]); } assertEquals(control, test); } }, taskOwner); } @Test public void testRepeatedPutAndRemove() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { Map<Integer,Integer> test = new ScalableHashMap<Integer,Integer>(1); Map<Integer,Integer> control = new HashMap<Integer,Integer>(); int[] inputs = new int[400]; for (int i = 0; i < inputs.length; i++) { int j = RANDOM.nextInt(); inputs[i] = j; test.put(j,j); control.put(j,j); } assertEquals(control, test); for (int i = 0; i < inputs.length; i += 4) { test.remove(inputs[i]); control.remove(inputs[i]); } assertEquals(control, test); for (int i = 0; i < inputs.length; i += 3) { test.put(inputs[i],inputs[i]); control.put(inputs[i],inputs[i]); } assertEquals(control, test); for (int i = 0; i < inputs.length; i += 2) { test.remove(inputs[i]); control.remove(inputs[i]); } assertEquals(control, test); } }, taskOwner); } @Test public void testRepeatedPutAndRemoveWithNoMergeAndNoCollapse() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { Map<Integer,Integer> test = createScalableHashMap(Integer.class, Integer.class, 1,32, 2); Map<Integer,Integer> control = new HashMap<Integer,Integer>(); int[] inputs = new int[1024]; for (int i = 0; i < inputs.length; i++) { int j = RANDOM.nextInt(); inputs[i] = j; test.put(j,j); control.put(j,j); } checkEquals(control, test); assertEquals(control, test); for (int i = 0; i < inputs.length; i += 4) { test.remove(inputs[i]); control.remove(inputs[i]); } checkEquals(control, test); assertEquals(control, test); for (int i = 0; i < inputs.length; i += 3) { test.put(inputs[i],inputs[i]); control.put(inputs[i],inputs[i]); } checkEquals(control, test); assertEquals(control, test); for (int i = 0; i < inputs.length; i += 2) { test.remove(inputs[i]); control.remove(inputs[i]); } assertEquals(control, test); } }, taskOwner); } @Test public void testRepeatedPutAndRemoveWithNoMergeAndCollapse() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { Map<Integer,Integer> test = createScalableHashMap(Integer.class, Integer.class, 1,32,4); Map<Integer,Integer> control = new HashMap<Integer,Integer>(); int[] inputs = new int[400]; for (int i = 0; i < inputs.length; i++) { int j = RANDOM.nextInt(); inputs[i] = j; test.put(j,j); control.put(j,j); } assertEquals(control, test); for (int i = 0; i < inputs.length; i += 4) { test.remove(inputs[i]); control.remove(inputs[i]); } assertEquals(control, test); for (int i = 0; i < inputs.length; i += 3) { test.put(inputs[i],inputs[i]); control.put(inputs[i],inputs[i]); } assertEquals(control, test); for (int i = 0; i < inputs.length; i += 2) { test.remove(inputs[i]); control.remove(inputs[i]); } assertEquals(control, test); } }, taskOwner); } @Test public void testPutAndRemoveOnSplitTree5() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap<Integer,Integer> test = new ScalableHashMap<Integer,Integer>(16); Map<Integer,Integer> control = new HashMap<Integer,Integer>(); int[] inputs = new int[50]; for (int i = 0; i < inputs.length; i++) inputs[i] = RANDOM.nextInt(); for (int i = 0; i < inputs.length; i++) { int j = RANDOM.nextInt(inputs.length); test.put(inputs[j], inputs[j]); control.put(inputs[j], inputs[j]); assertEquals(control, test); checkLeafRefs(test); int k = RANDOM.nextInt(inputs.length); test.remove(inputs[k]); control.remove(inputs[k]); assertEquals(control, test); checkLeafRefs(test); int m = RANDOM.nextInt(inputs.length); test.put(inputs[m], inputs[m]); control.put(inputs[m], inputs[m]); assertEquals(control, test); checkLeafRefs(test); } } }, taskOwner); } @Test public void testInvalidGet() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { Map<Integer,Integer> test = new ScalableHashMap<Integer,Integer>(); // put in numbers for (int i = 4000; i < 4100; i++) { test.put(i, i); } // get from outside the range of the put for (int i = 0; i < 100; i++) { assertEquals(null,test.get(i)); } } }, taskOwner); } /* * Test size */ @Test public void testLeafSize() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { Map<Integer,Integer> test = new ScalableHashMap<Integer,Integer>(); assertEquals(0, test.size()); assertTrue(test.isEmpty()); for (int i = 0; i < 128; i++) { test.put(i, i); } assertEquals(128, test.size()); assertFalse(test.isEmpty()); // remove the evens for (int i = 0; i < 128; i += 2) { test.remove(i); } assertEquals(64, test.size()); assertFalse(test.isEmpty()); // remove the odds for (int i = 1; i < 128; i += 2) { test.remove(i); } assertEquals(0, test.size()); assertTrue(test.isEmpty()); } }, taskOwner); } @Test public void testLeafSizeAfterRemove() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { Map<Integer,Integer> test = new ScalableHashMap<Integer,Integer>(); int SAMPLE_SIZE = 10; int[] inputs1 = new int[SAMPLE_SIZE]; int[] inputs2 = new int[SAMPLE_SIZE]; int[] inputs3 = new int[SAMPLE_SIZE]; for (int i = 0; i < inputs1.length; i++) { inputs1[i] = RANDOM.nextInt(); inputs2[i] = RANDOM.nextInt(); inputs3[i] = RANDOM.nextInt(); } for (int i = 0; i < inputs1.length; i++) { test.put(inputs1[i], inputs1[i]); test.put(inputs2[i], inputs2[i]); assertEquals(test.size(), (i+1)*2); } for (int i = 0; i < inputs1.length; i++) { int beforeSize = test.size(); test.put(inputs3[i], inputs3[i]); test.remove(inputs2[i]); assertEquals(beforeSize, test.size()); } } }, taskOwner); } @Test public void testTreeSizeOnSplitTree() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { // create a tree with an artificially small leaf size Map<Integer,Integer> test = new ScalableHashMap<Integer,Integer>(16); assertEquals(0, test.size()); for (int i = 0; i < 5; i++) { test.put(i, i); } assertEquals(5, test.size()); for (int i = 5; i < 15; i++) { test.put(i,i); } assertEquals(15, test.size()); for (int i = 15; i < 31; i++) { test.put(i,i); } assertEquals(31, test.size()); } }, taskOwner); } @Test public void testTreeSizeOnSplitTreeWithRemovals() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { // create a tree with an artificially small leaf size ScalableHashMap<Integer,Integer> test = new ScalableHashMap<Integer,Integer>(16); assertEquals(0, test.size()); int[] inserts = new int[128]; for (int i = 0; i < inserts.length; i++) { inserts[i] = RANDOM.nextInt(); } // add 32 for (int i = 0; i < 32; i++) { test.put(inserts[i], inserts[i]); } assertEquals(32, test.size()); // remove 10 for (int i = 0; i < 10; i++) { test.remove(inserts[i]); } assertEquals(22, test.size()); // add 32 for (int i = 32; i < 64; i++) { test.put(inserts[i],inserts[i]); } assertEquals(54, test.size()); // remove 10 for (int i = 32; i < 42; i++) { test.remove(inserts[i]); } // add 64 for (int i = 64; i < 128; i++) { test.put(inserts[i],inserts[i]); } assertEquals(108, test.size()); // remove 5 for (int i = 64; i < 69; i++) { test.remove(inserts[i]); } assertEquals(103, test.size()); } }, taskOwner); } /* * Test iterators */ @Test public void testIteratorRemove() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { Map<Integer,Foo> test = new ScalableHashMap<Integer,Foo>(); Set<Integer> keys = test.keySet(); Iterator<Integer> keysIter = keys.iterator(); try { keysIter.remove(); fail("Expected IllegalStateException"); } catch (IllegalStateException e) { } try { keysIter.next(); fail("Expected NoSuchElementException"); } catch (NoSuchElementException e) { } try { keysIter.remove(); fail("Expected IllegalStateException"); } catch (IllegalStateException e) { } test.put(1, new Foo(1)); test.put(2, new Foo(2)); keysIter = keys.iterator(); assertEquals(new Integer(1), keysIter.next()); keysIter.remove(); assertEquals(1, test.size()); assertTrue(test.containsKey(2)); try { keysIter.remove(); fail("Expected IllegalStateException"); } catch (IllegalStateException e) { } assertEquals(new Integer(2), keysIter.next()); keysIter.remove(); assertTrue(test.isEmpty()); try { keysIter.remove(); fail("Expected IllegalStateException"); } catch (IllegalStateException e) { } assertIteratorDone(keysIter); } }, taskOwner); } @SuppressWarnings("unchecked") @Test public void testIteratorNotFound() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap test = new ScalableHashMap(); dataService.setBinding("test", test); Bar bar = new Bar(1); dataService.setBinding("bar", bar); test.put(1, bar); test.put(2, new Bar(2)); } }, taskOwner); for (int i = 0; i < 2; i++) { final int local = i; txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap test = (ScalableHashMap) dataService.getBinding("test"); dataService.setBinding("valuesIter", new ManagedSerializable(test.values().iterator())); } }, taskOwner); txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { if (local == 0) { dataService.removeObject( dataService.getBinding("bar")); } ManagedSerializable<Iterator> ms = uncheckedCast( dataService.getBinding("valuesIter")); dataService.markForUpdate(ms); Iterator valuesIter = ms.get(); int count = 0; while (valuesIter.hasNext()) { count++; try { assertEquals(new Bar(2), valuesIter.next()); } catch (ObjectNotFoundException e) { } } assertEquals(2, count); } }, taskOwner); } } @Test public void testIteratorOnSplitTree() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { Map<Integer,Integer> test = new ScalableHashMap<Integer,Integer>(16); Set<Integer> control = new HashSet<Integer>(); // get from outside the range of the put for (int i = 0; i < 33; i++) { int j = RANDOM.nextInt(); test.put(j,j); control.add(j); } for (Integer i : test.keySet()) { control.remove(i); } assertEquals(0, control.size()); } }, taskOwner); } @Test public void testIteratorOnSplitTreeWithRemovals() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { // create a tree with an artificially small leaf size ScalableHashMap<Integer,Integer> test = new ScalableHashMap<Integer,Integer>(16); HashMap<Integer,Integer> control = new HashMap<Integer,Integer>(); assertEquals(0, test.size()); int[] inserts = new int[128]; for (int i = 0; i < inserts.length; i++) { inserts[i] = RANDOM.nextInt(); } // add 32 for (int i = 0; i < 32; i++) { test.put(inserts[i], inserts[i]); control.put(inserts[i], inserts[i]); } assertEquals(control, test); checkLeafRefs(test); // remove 10 for (int i = 0; i < 10; i++) { test.remove(inserts[i]); control.remove(inserts[i]); } assertEquals(control, test); checkLeafRefs(test); // add 32 for (int i = 32; i < 64; i++) { test.put(inserts[i],inserts[i]); control.put(inserts[i],inserts[i]); } assertEquals(control, test); checkLeafRefs(test); // remove 10 for (int i = 32; i < 42; i++) { test.remove(inserts[i]); control.remove(inserts[i]); } assertEquals(control, test); checkLeafRefs(test); // add 64 for (int i = 64; i < 128; i++) { test.put(inserts[i],inserts[i]); control.put(inserts[i],inserts[i]); } assertEquals(control, test); checkLeafRefs(test); // remove 5 for (int i = 64; i < 69; i++) { test.remove(inserts[i]); control.remove(inserts[i]); } assertEquals(control, test); checkLeafRefs(test); } }, taskOwner); } @Test public void testKeyIterator() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { Map<Integer,Integer> test = new ScalableHashMap<Integer,Integer>(); Set<Integer> control = new HashSet<Integer>(); // get from outside the range of the put for (int i = 0; i < 100; i++) { test.put(i,i); control.add(i); } for (Integer i : test.keySet()) { control.remove(i); } assertEquals(0, control.size()); } }, taskOwner); } @Test public void testKeyIteratorOnSplitMap() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { Map<Integer,Integer> test = new ScalableHashMap<Integer,Integer>(16); Set<Integer> control = new HashSet<Integer>(); // get from outside the range of the put for (int i = 0; i < 33; i++) { test.put(i,i); control.add(i); } for (Integer i : test.keySet()) { control.remove(i); } assertEquals(0, control.size()); } }, taskOwner); } @Test public void testValuesIterator() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { Map<Integer,Integer> test = new ScalableHashMap<Integer,Integer>(); Set<Integer> control = new HashSet<Integer>(); // get from outside the range of the put for (int i = 0; i < 100; i++) { test.put(i,i); control.add(i); } for (Integer i : test.values()) { control.remove(i); } assertEquals(0, control.size()); } }, taskOwner); } @Test public void testValuesIteratorOnSplitMap() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { Map<Integer,Integer> test = new ScalableHashMap<Integer,Integer>(16); Set<Integer> control = new HashSet<Integer>(); // get from outside the range of the put for (int i = 0; i < 33; i++) { test.put(i,i); control.add(i); } for (Integer i : test.values()) { control.remove(i); } assertEquals(0, control.size()); } }, taskOwner); } @Test public void testInvalidRemove() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { Map<Integer,Integer> test = new ScalableHashMap<Integer,Integer>(); // put in numbers for (int i = 4000; i < 4100; i++) { test.put(i, i); } // get from outside the range of the put for (int i = 0; i < 100; i++) { assertEquals(null, test.remove(i)); } } }, taskOwner); } @SuppressWarnings("unchecked") @Test public void testLeafSerialization() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { Map<Integer,Integer> test = new ScalableHashMap<Integer,Integer>(); Map<Integer,Integer> control = new HashMap<Integer,Integer>(); int[] a = new int[100]; for (int i = 0; i < a.length; i++) { int j = RANDOM.nextInt(); test.put(j, j); control.put(j, j); a[i] = j; } ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(test); byte[] serializedForm = baos.toByteArray(); ByteArrayInputStream bais = new ByteArrayInputStream(serializedForm); ObjectInputStream ois = new ObjectInputStream(bais); ScalableHashMap<Integer,Integer> m = (ScalableHashMap<Integer,Integer>) ois.readObject(); assertEquals(control, m); } }, taskOwner); } @SuppressWarnings("unchecked") @Test public void testSplitTreeSerialization() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { Map<Integer,Integer> test = new ScalableHashMap<Integer,Integer>(16); Map<Integer,Integer> control = new HashMap<Integer,Integer>(); int[] a = new int[100]; for (int i = 0; i < a.length; i++) { int j = RANDOM.nextInt(); test.put(j, j); control.put(j, j); a[i] = j; } ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(test); byte[] serializedForm = baos.toByteArray(); ByteArrayInputStream bais = new ByteArrayInputStream(serializedForm); ObjectInputStream ois = new ObjectInputStream(bais); ScalableHashMap<Integer,Integer> m = (ScalableHashMap<Integer,Integer>) ois.readObject(); assertEquals(control, m); } }, taskOwner); } /* * Tests on ManagedObject vs. Serializable object keys * * These tests should expose any bugs in the ScalableHashMap.PrefixEntry * class, especially in the setValue() method. These should also expose * any bugs in the KeyValuePair class */ @Test public void testOnManagedObjectKeys() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { Map<Bar,Foo> test = new ScalableHashMap<Bar,Foo>(); Map<Bar,Foo> control = new HashMap<Bar,Foo>(); for (int i = 0; i < 64; i++) { test.put(new Bar(i), new Foo(i)); control.put(new Bar(i), new Foo(i)); assertEquals(control, test); } } }, taskOwner); } @Test public void testOnManagedObjectValues() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { Map<Foo,Bar> test = new ScalableHashMap<Foo,Bar>(); Map<Foo,Bar> control = new HashMap<Foo,Bar>(); for (int i = 0; i < 64; i++) { test.put(new Foo(i), new Bar(i)); control.put(new Foo(i), new Bar(i)); assertEquals(control, test); } } }, taskOwner); } @Test public void testOnManagedObjectKeysAndValues() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { Map<Bar,Bar> test = new ScalableHashMap<Bar,Bar>(); Map<Bar,Bar> control = new HashMap<Bar,Bar>(); for (int i = 0; i < 64; i++) { test.put(new Bar(i), new Bar(i)); control.put(new Bar(i), new Bar(i)); assertEquals(control, test); } } }, taskOwner); } @Test public void testSerializableKeysReplacedWithManagedObjects() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { Map<Foo,Foo> test = new ScalableHashMap<Foo,Foo>(); Map<Foo,Foo> control = new HashMap<Foo,Foo>(); for (int i = 0; i < 64; i++) { test.put(new Foo(i), new Foo(i)); control.put(new Foo(i), new Foo(i)); assertEquals(control, test); } for (int i = 0; i < 64; i++) { test.put(new Bar(i), new Foo(i)); control.put(new Bar(i), new Foo(i)); assertEquals(control, test); } } }, taskOwner); } @Test public void testSerializableValuesReplacedWithManagedObjects() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { Map<Foo,Foo> test = new ScalableHashMap<Foo,Foo>(); Map<Foo,Foo> control = new HashMap<Foo,Foo>(); for (int i = 0; i < 64; i++) { test.put(new Foo(i), new Foo(i)); control.put(new Foo(i), new Foo(i)); assertEquals(control, test); } for (int i = 0; i < 64; i++) { test.put(new Foo(i), new Bar(i)); control.put(new Foo(i), new Bar(i)); assertEquals(control, test); } } }, taskOwner); } /* * Concurrent Iterator tests * * These tests should expose any problems when the * ScalableHashMap.ConcurrentIterator class is serialized and modifications * are made to the map before it is deserialized. This should simulate the * conditions between transactions where the map might be modified */ @SuppressWarnings("unchecked") @Test public void testConcurrentIterator() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap<Integer,Integer> test = new ScalableHashMap<Integer,Integer>(16); Map<Integer,Integer> control = new HashMap<Integer,Integer>(); int[] a = new int[128]; for (int i = 0; i < a.length; i++) { int j = RANDOM.nextInt(); test.put(j, j); control.put(j, j); a[i] = j; } Set<Map.Entry<Integer,Integer>> entrySet = control.entrySet(); int entries = 0; for (Iterator<Map.Entry<Integer,Integer>> it = test.entrySet().iterator(); it.hasNext(); ) { Map.Entry<Integer,Integer> e = it.next(); assertTrue(entrySet.contains(e)); entries++; } assertEquals(entrySet.size(), entries); } }, taskOwner); } @SuppressWarnings("unchecked") @Test public void testConcurrentIteratorSerialization() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap<Integer,Integer> test = new ScalableHashMap<Integer,Integer>(16); Map<Integer,Integer> control = new HashMap<Integer,Integer>(); int[] a = new int[256]; for (int i = 0; i < a.length; i++) { int j = RANDOM.nextInt(); test.put(j, j); control.put(j, j); a[i] = j; } Set<Map.Entry<Integer,Integer>> entrySet = control.entrySet(); int entries = 0; Iterator<Map.Entry<Integer,Integer>> it = test.entrySet().iterator(); for (int i = 0; i < a.length / 2; i++) { Map.Entry<Integer,Integer> e = it.next(); assertTrue(entrySet.contains(e)); entries++; } ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(it); byte[] serializedForm = baos.toByteArray(); ByteArrayInputStream bais = new ByteArrayInputStream(serializedForm); ObjectInputStream ois = new ObjectInputStream(bais); it = (Iterator<Map.Entry<Integer,Integer>>) ois.readObject(); while(it.hasNext()) { Map.Entry<Integer,Integer> e = it.next(); assertTrue(entrySet.contains(e)); entries++; } assertEquals(entrySet.size(), entries); } }, taskOwner); } @SuppressWarnings("unchecked") @Test public void testConcurrentIteratorWithRemovals() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap<Integer,Integer> test = new ScalableHashMap<Integer,Integer>(16); Map<Integer,Integer> control = new HashMap<Integer,Integer>(); int[] a = new int[1024]; for (int i = 0; i < a.length; i++) { int j = RANDOM.nextInt(); test.put(j, j); control.put(j, j); a[i] = j; } Set<Map.Entry<Integer,Integer>> entrySet = control.entrySet(); int entries = 0; Iterator<Map.Entry<Integer,Integer>> it = test.entrySet().iterator(); // serialize the iterator ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(it); // then remove half of the entries for (int i = 0; i < a.length; i += 2) { test.remove(a[i]); control.remove(a[i]); } byte[] serializedForm = baos.toByteArray(); ByteArrayInputStream bais = new ByteArrayInputStream(serializedForm); ObjectInputStream ois = new ObjectInputStream(bais); it = (Iterator<Map.Entry<Integer,Integer>>) ois.readObject(); // ensure that the deserialized iterator reads the // remaining elements while(it.hasNext()) { Map.Entry<Integer,Integer> e = it.next(); e.getKey(); assertTrue(entrySet.contains(e)); entries++; } assertEquals(entrySet.size(), entries); } }, taskOwner); } @SuppressWarnings("unchecked") @Test public void testConcurrentIteratorWithAdditions() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap<Integer,Integer> test = new ScalableHashMap<Integer,Integer>(16); Map<Integer,Integer> control = new HashMap<Integer,Integer>(); // immediately get the iterator while the map size is zero Iterator<Map.Entry<Integer,Integer>> it = test.entrySet().iterator(); // serialize the iterator ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(it); int[] a = new int[128]; for (int i = 0; i < a.length; i++) { int j = RANDOM.nextInt(); test.put(j, j); control.put(j, j); a[i] = j; } Set<Map.Entry<Integer,Integer>> entrySet = control.entrySet(); int entries = 0; byte[] serializedForm = baos.toByteArray(); ByteArrayInputStream bais = new ByteArrayInputStream(serializedForm); ObjectInputStream ois = new ObjectInputStream(bais); it = (Iterator<Map.Entry<Integer,Integer>>) ois.readObject(); // ensure that the deserialized iterator reads all of // the new elements while(it.hasNext()) { Map.Entry<Integer,Integer> e = it.next(); assertTrue(entrySet.contains(e)); entries++; } assertEquals(entrySet.size(), entries); } }, taskOwner); } @SuppressWarnings("unchecked") @Test public void testConcurrentIteratorWithReplacements() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap<Integer,Integer> test = new ScalableHashMap<Integer,Integer>(16); Map<Integer,Integer> control = new HashMap<Integer,Integer>(); int[] a = new int[128]; for (int i = 0; i < a.length; i++) { int j = RANDOM.nextInt(); test.put(j, j); control.put(j, j); a[i] = j; } Set<Map.Entry<Integer,Integer>> entrySet = control.entrySet(); int entries = 0; Iterator<Map.Entry<Integer,Integer>> it = test.entrySet().iterator(); for (int i = 0; i < a.length / 2; i++) { Map.Entry<Integer,Integer> e = it.next(); assertTrue(entrySet.contains(e)); entries++; } assertEquals(a.length / 2, entries); // serialize the iterator ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(it); // now replace all the elements in the map DoneRemoving.init(); test.clear(); control.clear(); for (int i = 0; i < a.length; i++) { int j = RANDOM.nextInt(); test.put(j, j); control.put(j, j); a[i] = j; } // reserialize the iterator byte[] serializedForm = baos.toByteArray(); ByteArrayInputStream bais = new ByteArrayInputStream(serializedForm); ObjectInputStream ois = new ObjectInputStream(bais); it = (Iterator<Map.Entry<Integer,Integer>>) ois.readObject(); while(it.hasNext()) { Map.Entry<Integer,Integer> e = it.next(); assertTrue(entrySet.contains(e)); entries++; } // due to the random nature of the entries, we can't check // that it read in another half other elements. However // this should still check that no execptions were thrown. } }, taskOwner); DoneRemoving.await(1); } /* * Tests on concurrent iterator edge cases */ @SuppressWarnings("unchecked") @Test public void testConcurrentIteratorSerializationEqualHashCodes() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap<Equals,Integer> test = new ScalableHashMap<Equals,Integer>(16); Map<Equals,Integer> control = new HashMap<Equals,Integer>(); int[] a = new int[256]; for (int i = 0; i < a.length; i++) { int j = RANDOM.nextInt(); test.put(new Equals(j), j); control.put(new Equals(j), j); a[i] = j; } Iterator<Map.Entry<Equals,Integer>> it = test.entrySet().iterator(); for (int i = 0; i < a.length / 2; i++) { Map.Entry<Equals,Integer> e = it.next(); assertTrue(control.remove(e.getKey()) != null); } ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(it); byte[] serializedForm = baos.toByteArray(); ByteArrayInputStream bais = new ByteArrayInputStream(serializedForm); ObjectInputStream ois = new ObjectInputStream(bais); it = (Iterator<Map.Entry<Equals,Integer>>) ois.readObject(); while(it.hasNext()) { Map.Entry<Equals,Integer> e = it.next(); assertTrue(control.remove(e.getKey()) != null); } assertEquals(0, control.size()); } }, taskOwner); } @SuppressWarnings("unchecked") @Test public void testConcurrentIteratorWithRemovalsEqualHashCodes() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap<Equals,Integer> test = new ScalableHashMap<Equals,Integer>(16); Map<Equals,Integer> control = new HashMap<Equals,Integer>(); int[] a = new int[128]; for (int i = 0; i < a.length; i++) { int j = RANDOM.nextInt(); test.put(new Equals(j), j); control.put(new Equals(j), j); a[i] = j; } Set<Map.Entry<Equals,Integer>> entrySet = control.entrySet(); int entries = 0; Iterator<Map.Entry<Equals,Integer>> it = test.entrySet().iterator(); // serialize the iterator ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(it); // then remove half of the entries for (int i = 0; i < a.length; i += 2) { test.remove(a[i]); control.remove(a[i]); } byte[] serializedForm = baos.toByteArray(); ByteArrayInputStream bais = new ByteArrayInputStream(serializedForm); ObjectInputStream ois = new ObjectInputStream(bais); it = (Iterator<Map.Entry<Equals,Integer>>) ois.readObject(); // ensure that the deserialized iterator reads the // remaining elements while(it.hasNext()) { Map.Entry<Equals,Integer> e = it.next(); assertTrue(entrySet.contains(e)); entries++; } assertEquals(entrySet.size(), entries); } }, taskOwner); } @SuppressWarnings("unchecked") @Test public void testConcurrentIteratorWithAdditionsEqualHashCodes() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap<Equals,Integer> test = new ScalableHashMap<Equals,Integer>(16); Map<Equals,Integer> control = new HashMap<Equals,Integer>(); // immediately get the iterator while the map size is zero Iterator<Map.Entry<Equals,Integer>> it = test.entrySet().iterator(); // serialize the iterator ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(it); int[] a = new int[128]; for (int i = 0; i < a.length; i++) { int j = RANDOM.nextInt(); test.put(new Equals(j), j); control.put(new Equals(j), j); a[i] = j; } int entries = 0; byte[] serializedForm = baos.toByteArray(); ByteArrayInputStream bais = new ByteArrayInputStream(serializedForm); ObjectInputStream ois = new ObjectInputStream(bais); it = (Iterator<Map.Entry<Equals,Integer>>) ois.readObject(); // ensure that the deserialized iterator reads all of // the new elements while(it.hasNext()) { Map.Entry<Equals,Integer> e = it.next(); control.remove(e.getKey()); } assertEquals(0, control.size()); } }, taskOwner); } @SuppressWarnings("unchecked") @Test public void testConcurrentIteratorWithReplacementsOnEqualHashCodes() throws Exception { txnScheduler.runTask( new TestAbstractKernelRunnable() { public void run() throws Exception { ScalableHashMap<Equals,Integer> test = new ScalableHashMap<Equals,Integer>(16); Map<Equals,Integer> control = new HashMap<Equals,Integer>(); int[] a = new int[128]; for (int i = 0; i < a.length; i++) { int j = RANDOM.nextInt(); test.put(new Equals(j), j); control.put(new Equals(j), j); a[i] = j; } Set<Map.Entry<Equals,Integer>> entrySet = control.entrySet(); int entries = 0; Iterator<Map.Entry<Equals,Integer>> it = test.entrySet().iterator(); for (int i = 0; i < a.length / 2; i++) { Map.Entry<Equals,Integer> e = it.next(); assertTrue(entrySet.contains(e)); entries++; } assertEquals(a.length / 2, entries); // serialize the iterator ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(it); // now replace all the elements in the map DoneRemoving.init(); test.clear(); control.clear(); for (int i = 0; i < a.length; i++) { int j = RANDOM.nextInt(); test.put(new Equals(j), j); control.put(new Equals(j), j); a[i] = j; } assertEquals(control.size(), test.size()); // reserialize the iterator byte[] serializedForm = baos.toByteArray(); ByteArrayInputStream bais = new ByteArrayInputStream(serializedForm); ObjectInputStream ois = new ObjectInputStream(bais); it = (Iterator<Map.Entry<Equals,Integer>>) ois.readObject(); while (it.hasNext()) { Map.Entry<Equals,Integer> e = it.next(); assertTrue(entrySet.contains(e)); entries++; } // due to the random nature of the entries, we can't check // that it read in another half other elements. However // this should still check that no exceptions were thrown. } }, taskOwner); DoneRemoving.await(1); } /* * Utility routines. */ public boolean checkEquals(Map<Integer,Integer> m1, Map<Integer,Integer> m2) { if (m1.size() != m2.size()) { System.out.printf("sizes not equal: %d != %d\n", m1.size(), m2.size()); return false; } Iterator<Entry<Integer,Integer>> i = m1.entrySet().iterator(); while (i.hasNext()) { Entry<Integer,Integer> e = i.next(); Integer key = e.getKey(); Integer value = e.getValue(); if (value == null) { if (!(m2.get(key)==null && m2.containsKey(key))) { System.out.printf("keys not equal, m2 has key: %s? %s\n", key, m2.containsKey(key)); return false; } } else { if (!value.equals(m2.get(key))) { System.out.printf("m1.get(%s) not equal: %s: %s\n", key, value, m2.get(key)); System.out.println("m2.containsKey() ? " + m2.containsKey(key)); return false; } } } return true; } /** * Constructs an empty {@code ScalableHashMap} by calling the private * constructor to supply additional parameters. */ @SuppressWarnings("unchecked") private static <K,V> ScalableHashMap<K,V> createScalableHashMap( Class<K> keyClass, Class<V> valueClass, int minConcurrency, int splitThreshold, int directorySize) { int minDepth = findMinDepthFor(minConcurrency); try { return (ScalableHashMap<K,V>) scalableHashMapConstructor.newInstance( 0, minDepth, splitThreshold, directorySize); } catch (InvocationTargetException e) { throw (RuntimeException) e.getCause(); } catch (Exception e) { throw new RuntimeException("Unexpected exception: " + e, e); } } /** * Returns the minimum depth of the tree necessary to support the requested * minimum number of concurrent write operations. */ private static int findMinDepthFor(int minConcurrency) { try { return (Integer) findMinDepthFor.invoke(null, minConcurrency); } catch (InvocationTargetException e) { throw (RuntimeException) e.getCause(); } catch (Exception e) { throw new RuntimeException("Unexpected exception: " + e, e); } } /** * Returns the minimum depth for any leaf node in the map's backing tree. * The root node has a depth of 1. */ private int getMinTreeDepth(ScalableHashMap map) { try { return (Integer) getMinTreeDepth.invoke(map); } catch (Exception e) { throw new RuntimeException("Unexpected exception: " + e, e); } } /** * Returns the maximum depth for any leaf node in the map's backing tree. * The root node has a depth of 1. */ private int getMaxTreeDepth(ScalableHashMap map) { try { return (Integer) getMaxTreeDepth.invoke(map); } catch (Exception e) { throw new RuntimeException("Unexpected exception: " + e, e); } } /** * Returns the average of all depth for the leaf nodes in the map's backing * tree. The root node has a depth of 1. */ private double getAvgTreeDepth(ScalableHashMap map) { try { return (Integer) getAvgTreeDepth.invoke(map); } catch (Exception e) { throw new RuntimeException("Unexpected exception: " + e, e); } } /** * Verifies the state of the doubly linked list of the map's leaf nodes. */ private void checkLeafRefs(ScalableHashMap map) { try { checkLeafRefs.invoke(map); } catch (Exception e) { throw new RuntimeException("Unexpected exception: " + e, e); } } /** Checks that the iterator has no more entries. */ private static void assertIteratorDone(Iterator<?> iterator) { assertFalse(iterator.hasNext()); try { iterator.next(); fail("Expected NoSuchElementException"); } catch (NoSuchElementException e) { } } /** * Checks that the iterator returns objects equal to the contents of the * collection. */ private static void assertIteratorContains( Collection<?> contents, Iterator<?> iterator) { Set<?> set = new HashSet<Object>(contents); while (iterator.hasNext()) { assertTrue(set.remove(iterator.next())); } assertTrue(set.isEmpty()); } private static Properties createProps(String appName) throws Exception { Properties props = SgsTestNode.getDefaultProperties(appName, null, SgsTestNode.DummyAppListener.class); props.setProperty("com.sun.sgs.txn.timeout", "1000000"); return props; } /* * Test classes */ /** * A serializable object that is equal to objects of the same type with the * same value. */ static class Foo implements Serializable { private static final long serialVersionUID = 1L; private final int i; Foo(int i) { this.i = i; } public int hashCode() { return i; } public boolean equals(Object o) { return o != null && getClass() == o.getClass() && ((Foo) o).i == i; } } /** * A managed object that is equal to objects of the same type with the * same value. */ static class Bar extends Foo implements ManagedObject { private static final long serialVersionUID = 1L; Bar(int i) { super(i); } } /** * A serializable object that is equal to objects of the same type with the * type, but whose hashCode method always returns zero. */ static class Equals extends Foo { private static final long serialVersionUID = 1L; Equals(int i) { super(i); } public int hashCode() { return 0; } } }