/*
* Copyright (c) 2008-2017, Hazelcast, Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hazelcast.map;
import com.hazelcast.config.Config;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.map.impl.proxy.MapProxyImpl;
import com.hazelcast.spi.properties.GroupProperty;
import com.hazelcast.test.HazelcastParametersRunnerFactory;
import com.hazelcast.test.HazelcastTestSupport;
import com.hazelcast.test.TestHazelcastInstanceFactory;
import com.hazelcast.test.annotation.ParallelTest;
import com.hazelcast.test.annotation.QuickTest;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
import static org.junit.Assert.assertEquals;
@RunWith(Parameterized.class)
@Parameterized.UseParametersRunnerFactory(HazelcastParametersRunnerFactory.class)
@Category({QuickTest.class, ParallelTest.class})
public class MapPartitionIteratorTest extends HazelcastTestSupport {
@Parameter
public boolean prefetchValues;
@Parameters(name = "prefetchValues:{0}")
public static Iterable<Object[]> parameters() {
return Arrays.asList(new Object[]{Boolean.TRUE}, new Object[]{Boolean.FALSE});
}
@Test(expected = NoSuchElementException.class)
public void test_next_Throws_Exception_On_EmptyPartition() throws Exception {
HazelcastInstance instance = createHazelcastInstance();
MapProxyImpl<Object, Object> proxy = (MapProxyImpl<Object, Object>) instance.getMap(randomMapName());
Iterator<Map.Entry<Object, Object>> iterator = proxy.iterator(10, 1, prefetchValues);
iterator.next();
}
@Test(expected = IllegalStateException.class)
public void test_remove_Throws_Exception_When_Called_Without_Next() throws Exception {
HazelcastInstance instance = createHazelcastInstance();
MapProxyImpl<Object, Object> proxy = (MapProxyImpl<Object, Object>) instance.getMap(randomMapName());
Iterator<Map.Entry<Object, Object>> iterator = proxy.iterator(10, 1, prefetchValues);
iterator.remove();
}
@Test
public void test_Remove() throws Exception {
HazelcastInstance instance = createHazelcastInstance();
MapProxyImpl<Object, Object> proxy = (MapProxyImpl<Object, Object>) instance.getMap(randomMapName());
String key = generateKeyForPartition(instance, 1);
String value = randomString();
proxy.put(key, value);
Iterator<Map.Entry<Object, Object>> iterator = proxy.iterator(10, 1, prefetchValues);
iterator.next();
iterator.remove();
assertEquals(0, proxy.size());
}
@Test
public void test_HasNext_Returns_False_On_EmptyPartition() throws Exception {
HazelcastInstance instance = createHazelcastInstance();
MapProxyImpl<Object, Object> proxy = (MapProxyImpl<Object, Object>) instance.getMap(randomMapName());
Iterator<Map.Entry<Object, Object>> iterator = proxy.iterator(10, 1, prefetchValues);
assertFalse(iterator.hasNext());
}
@Test
public void test_HasNext_Returns_True_On_NonEmptyPartition() throws Exception {
HazelcastInstance instance = createHazelcastInstance();
MapProxyImpl<Object, Object> proxy = (MapProxyImpl<Object, Object>) instance.getMap(randomMapName());
String key = generateKeyForPartition(instance, 1);
String value = randomString();
proxy.put(key, value);
Iterator<Map.Entry<Object, Object>> iterator = proxy.iterator(10, 1, prefetchValues);
assertTrue(iterator.hasNext());
}
@Test
public void test_Next_Returns_Value_On_NonEmptyPartition() throws Exception {
HazelcastInstance instance = createHazelcastInstance();
MapProxyImpl<Object, Object> proxy = (MapProxyImpl<Object, Object>) instance.getMap(randomMapName());
String key = generateKeyForPartition(instance, 1);
String value = randomString();
proxy.put(key, value);
Iterator<Map.Entry<Object, Object>> iterator = proxy.iterator(10, 1, prefetchValues);
Map.Entry entry = iterator.next();
assertEquals(value, entry.getValue());
}
@Test
public void test_Next_Returns_Value_On_NonEmptyPartition_and_HasNext_Returns_False_when_Item_Consumed() throws Exception {
HazelcastInstance instance = createHazelcastInstance();
MapProxyImpl<Object, Object> proxy = (MapProxyImpl<Object, Object>) instance.getMap(randomMapName());
String key = generateKeyForPartition(instance, 1);
String value = randomString();
proxy.put(key, value);
Iterator<Map.Entry<Object, Object>> iterator = proxy.iterator(10, 1, prefetchValues);
Map.Entry entry = iterator.next();
assertEquals(value, entry.getValue());
boolean hasNext = iterator.hasNext();
assertFalse(hasNext);
}
@Test
public void test_Next_Returns_Values_When_FetchSizeExceeds_On_NonEmptyPartition() throws Exception {
HazelcastInstance instance = createHazelcastInstance();
MapProxyImpl<Object, Object> proxy = (MapProxyImpl<Object, Object>) instance.getMap(randomMapName());
String value = randomString();
for (int i = 0; i < 100; i++) {
String key = generateKeyForPartition(instance, 1);
proxy.put(key, value);
}
Iterator<Map.Entry<Object, Object>> iterator = proxy.iterator(10, 1, prefetchValues);
for (int i = 0; i < 100; i++) {
Map.Entry entry = iterator.next();
assertEquals(value, entry.getValue());
}
}
@Test
@Ignore
public void test_DoesNotReturn_DuplicateEntry_When_Rehashing_Happens() throws Exception {
HazelcastInstance instance = createHazelcastInstance();
MapProxyImpl<String, String> proxy = (MapProxyImpl<String, String>) instance.<String, String>getMap(randomMapName());
HashSet<String> readKeys = new HashSet<String>();
String value = "initialValue";
putValuesToPartition(instance, proxy, value, 1, 100);
Iterator<Map.Entry<String, String>> iterator = proxy.iterator(10, 1, prefetchValues);
assertUniques(readKeys, iterator, 50);
// force rehashing
putValuesToPartition(instance, proxy, randomString(), 1, 150);
assertUniques(readKeys, iterator);
}
@Test
@Ignore
public void test_DoesNotReturn_DuplicateEntry_When_Migration_Happens() throws Exception {
Config config = getConfig();
config.setProperty(GroupProperty.PARTITION_COUNT.getName(), "2");
TestHazelcastInstanceFactory factory = createHazelcastInstanceFactory();
HazelcastInstance instance = factory.newHazelcastInstance(config);
MapProxyImpl<String, String> proxy = (MapProxyImpl<String, String>) instance.<String, String>getMap(randomMapName());
HashSet<String> readKeysP1 = new HashSet<String>();
HashSet<String> readKeysP2 = new HashSet<String>();
String value = "value";
putValuesToPartition(instance, proxy, value, 0, 100);
putValuesToPartition(instance, proxy, value, 1, 100);
Iterator<Map.Entry<String, String>> iteratorP1 = proxy.iterator(10, 0, prefetchValues);
Iterator<Map.Entry<String, String>> iteratorP2 = proxy.iterator(10, 1, prefetchValues);
assertUniques(readKeysP1, iteratorP1, 50);
assertUniques(readKeysP2, iteratorP2, 50);
// force migration
factory.newHazelcastInstance(config);
// force rehashing
putValuesToPartition(instance, proxy, randomString(), 0, 150);
putValuesToPartition(instance, proxy, randomString(), 1, 150);
assertUniques(readKeysP1, iteratorP1);
assertUniques(readKeysP2, iteratorP2);
}
private void assertUniques(HashSet<String> readKeys, Iterator<Map.Entry<String, String>> iterator) {
while (iterator.hasNext()) {
Map.Entry<String, String> entry = iterator.next();
boolean unique = readKeys.add(entry.getKey());
Assert.assertTrue(unique);
}
}
private void assertUniques(HashSet<String> readKeys, Iterator<Map.Entry<String, String>> iterator, int numberOfItemsToRead) {
int count = 0;
while (iterator.hasNext() && count++ < numberOfItemsToRead) {
Map.Entry<String, String> entry = iterator.next();
boolean unique = readKeys.add(entry.getKey());
Assert.assertTrue(unique);
}
}
private void putValuesToPartition(HazelcastInstance instance, MapProxyImpl<String, String> proxy, String value,
int partitionId, int count) {
for (int i = 0; i < count; i++) {
String key = generateKeyForPartition(instance, partitionId);
proxy.put(key, value);
}
}
}