/*
* 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.impl.mapstore;
import com.hazelcast.config.Config;
import com.hazelcast.config.EvictionPolicy;
import com.hazelcast.config.MapConfig;
import com.hazelcast.config.MaxSizeConfig;
import com.hazelcast.core.EntryAdapter;
import com.hazelcast.core.EntryEvent;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.core.IMap;
import com.hazelcast.instance.TestUtil;
import com.hazelcast.map.impl.mapstore.MapStoreTest.TestMapStore;
import com.hazelcast.map.impl.mapstore.MapStoreWriteBehindTest.FailAwareMapStore;
import com.hazelcast.query.SampleObjects.Employee;
import com.hazelcast.spi.properties.GroupProperty;
import com.hazelcast.test.HazelcastParallelClassRunner;
import com.hazelcast.test.TestHazelcastInstanceFactory;
import com.hazelcast.test.annotation.ParallelTest;
import com.hazelcast.test.annotation.QuickTest;
import com.hazelcast.util.EmptyStatement;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@RunWith(HazelcastParallelClassRunner.class)
@Category({QuickTest.class, ParallelTest.class})
public class MapStoreWriteThroughTest extends AbstractMapStoreTest {
@Test(timeout = 120000)
public void testOneMemberWriteThroughWithIndex() throws Exception {
TestMapStore testMapStore = new TestMapStore(1, 1, 1);
testMapStore.setLoadAllKeys(false);
Config config = newConfig(testMapStore, 0);
TestHazelcastInstanceFactory nodeFactory = createHazelcastInstanceFactory(3);
HazelcastInstance instance = nodeFactory.newHazelcastInstance(config);
testMapStore.insert("1", "value1");
IMap<String, String> map = instance.getMap("default");
assertEquals(0, map.size());
assertTrue(map.tryLock("1", 1, TimeUnit.SECONDS));
assertEquals("value1", map.get("1"));
map.unlock("1");
assertEquals("value1", map.put("1", "value2"));
assertEquals("value2", map.get("1"));
assertEquals("value2", testMapStore.getStore().get("1"));
assertEquals(1, map.size());
assertTrue(map.evict("1"));
assertEquals(0, map.size());
assertEquals(1, testMapStore.getStore().size());
assertEquals("value2", map.get("1"));
assertEquals(1, map.size());
map.remove("1");
assertEquals(0, map.size());
assertEquals(0, testMapStore.getStore().size());
testMapStore.assertAwait(1);
assertEquals(1, testMapStore.getInitCount());
assertEquals("default", testMapStore.getMapName());
assertEquals(TestUtil.getNode(instance), TestUtil.getNode(testMapStore.getHazelcastInstance()));
}
@Test(timeout = 120000)
public void testOneMemberWriteThroughWithLRU() throws Exception {
final int size = 10000;
TestMapStore testMapStore = new TestMapStore(size * 2, 1, 1);
testMapStore.setLoadAllKeys(false);
Config config = newConfig(testMapStore, 0);
config.setProperty(GroupProperty.PARTITION_COUNT.getName(), "1");
MaxSizeConfig maxSizeConfig = new MaxSizeConfig();
maxSizeConfig.setSize(size);
MapConfig mapConfig = config.getMapConfig("default");
mapConfig.setEvictionPolicy(EvictionPolicy.LRU);
mapConfig.setMaxSizeConfig(maxSizeConfig);
mapConfig.setMinEvictionCheckMillis(0);
TestHazelcastInstanceFactory nodeFactory = createHazelcastInstanceFactory(3);
HazelcastInstance instance = nodeFactory.newHazelcastInstance(config);
IMap<Integer, Employee> map = instance.getMap("default");
final CountDownLatch countDownLatch = new CountDownLatch(size);
map.addEntryListener(new EntryAdapter() {
@Override
public void entryEvicted(EntryEvent event) {
countDownLatch.countDown();
}
}, false);
for (int i = 0; i < size * 2; i++) {
// trigger eviction.
if (i == (size * 2) - 1 || i == size) {
sleepMillis(1001);
}
map.put(i, new Employee("joe", i, true, 100.00));
}
assertEquals(testMapStore.getStore().size(), size * 2);
assertOpenEventually(countDownLatch);
final String msgFailure = String.format("map size: %d put count: %d", map.size(), size);
assertTrue(msgFailure, map.size() > size / 2);
assertTrue(msgFailure, map.size() <= size);
assertEquals(testMapStore.getStore().size(), size * 2);
}
@Test(timeout = 120000)
public void testOneMemberWriteThrough() throws Exception {
TestMapStore testMapStore = new TestMapStore(1, 1, 1);
testMapStore.setLoadAllKeys(false);
Config config = newConfig(testMapStore, 0);
HazelcastInstance instance = createHazelcastInstance(config);
Employee employee = new Employee("joe", 25, true, 100.00);
Employee newEmployee = new Employee("ali", 26, true, 1000);
testMapStore.insert("1", employee);
testMapStore.insert("2", employee);
testMapStore.insert("3", employee);
testMapStore.insert("4", employee);
testMapStore.insert("5", employee);
testMapStore.insert("6", employee);
testMapStore.insert("7", employee);
IMap<String, Employee> map = instance.getMap("default");
map.addIndex("name", false);
assertEquals(0, map.size());
assertEquals(employee, map.get("1"));
assertEquals(employee, testMapStore.getStore().get("1"));
assertEquals(1, map.size());
assertEquals(employee, map.put("2", newEmployee));
assertEquals(newEmployee, testMapStore.getStore().get("2"));
assertEquals(2, map.size());
map.remove("1");
map.put("1", employee, 1, TimeUnit.SECONDS);
map.put("1", employee);
Thread.sleep(2000);
assertEquals(employee, testMapStore.getStore().get("1"));
assertEquals(employee, map.get("1"));
map.evict("2");
assertEquals(newEmployee, map.get("2"));
assertEquals(employee, map.get("3"));
assertEquals(employee, map.put("3", newEmployee));
assertEquals(newEmployee, map.get("3"));
assertEquals(employee, map.remove("4"));
assertEquals(employee, map.get("5"));
assertEquals(employee, map.remove("5"));
assertEquals(employee, map.putIfAbsent("6", newEmployee));
assertEquals(employee, map.get("6"));
assertEquals(employee, testMapStore.getStore().get("6"));
assertTrue(map.containsKey("7"));
assertEquals(employee, map.get("7"));
assertNull(map.get("8"));
assertFalse(map.containsKey("8"));
assertNull(map.putIfAbsent("8", employee));
assertEquals(employee, map.get("8"));
assertEquals(employee, testMapStore.getStore().get("8"));
}
@Test(timeout = 120000)
public void testTwoMemberWriteThrough() throws Exception {
TestMapStore testMapStore = new TestMapStore(1, 1, 1);
testMapStore.setLoadAllKeys(false);
Config config = newConfig(testMapStore, 0);
TestHazelcastInstanceFactory nodeFactory = createHazelcastInstanceFactory(3);
HazelcastInstance instance = nodeFactory.newHazelcastInstance(config);
nodeFactory.newHazelcastInstance(config);
Employee employee = new Employee("joe", 25, true, 100.00);
Employee employee2 = new Employee("jay", 35, false, 100.00);
testMapStore.insert("1", employee);
IMap<String, Employee> map = instance.getMap("default");
map.addIndex("name", false);
assertEquals(0, map.size());
assertEquals(employee, map.get("1"));
assertEquals(employee, testMapStore.getStore().get("1"));
assertEquals(1, map.size());
map.put("2", employee2);
assertEquals(employee2, testMapStore.getStore().get("2"));
assertEquals(2, testMapStore.getStore().size());
assertEquals(2, map.size());
map.remove("2");
assertEquals(1, testMapStore.getStore().size());
assertEquals(1, map.size());
testMapStore.assertAwait(10);
assertEquals(5, testMapStore.callCount.get());
}
@Test(timeout = 300000)
public void testTwoMemberWriteThrough2() throws Exception {
int items = 1000;
TestMapStore testMapStore = new TestMapStore(items, 0, 0);
Config config = newConfig(testMapStore, 0);
TestHazelcastInstanceFactory nodeFactory = createHazelcastInstanceFactory(3);
HazelcastInstance h1 = nodeFactory.newHazelcastInstance(config);
HazelcastInstance h2 = nodeFactory.newHazelcastInstance(config);
IMap<Integer, String> map1 = h1.getMap("default");
IMap<Integer, String> map2 = h2.getMap("default");
for (int i = 0; i < items; i++) {
map1.put(i, "value" + i);
}
assertTrue("store operations could not be done wisely ", testMapStore.latchStore.await(30, TimeUnit.SECONDS));
assertEquals(items, testMapStore.getStore().size());
assertEquals(items, map1.size());
assertEquals(items, map2.size());
testMapStore.assertAwait(10);
// N put-load N put-store call and 1 loadAllKeys
assertEquals(items * 2 + 1, testMapStore.callCount.get());
}
@Test(timeout = 120000)
public void testOneMemberWriteThroughFailingStore() throws Exception {
FailAwareMapStore testMapStore = new FailAwareMapStore();
testMapStore.setFail(true, true);
Config config = newConfig(testMapStore, 0);
TestHazelcastInstanceFactory nodeFactory = createHazelcastInstanceFactory(3);
HazelcastInstance instance = nodeFactory.newHazelcastInstance(config);
IMap<String, String> map = instance.getMap("default");
assertEquals(0, map.size());
try {
map.get("1");
fail("should have thrown exception");
} catch (Exception e) {
EmptyStatement.ignore(e);
}
assertEquals(1, testMapStore.loads.get());
try {
map.get("1");
fail("should have thrown exception");
} catch (Exception e) {
EmptyStatement.ignore(e);
}
assertEquals(2, testMapStore.loads.get());
try {
map.put("1", "value");
fail("should have thrown exception");
} catch (Exception e) {
EmptyStatement.ignore(e);
}
assertEquals(0, testMapStore.stores.get());
assertEquals(0, map.size());
}
@Test(timeout = 120000)
public void testOneMemberWriteThroughFailingStore2() throws Exception {
FailAwareMapStore testMapStore = new FailAwareMapStore();
testMapStore.setFail(true, false);
Config config = newConfig(testMapStore, 0);
TestHazelcastInstanceFactory nodeFactory = createHazelcastInstanceFactory(3);
HazelcastInstance instance = nodeFactory.newHazelcastInstance(config);
IMap<String, String> map = instance.getMap("default");
assertEquals(0, map.size());
try {
map.put("1", "value");
fail("should have thrown exception");
} catch (Exception e) {
EmptyStatement.ignore(e);
}
assertEquals(0, map.size());
}
}