/*
* 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.multimap;
import com.hazelcast.config.Config;
import com.hazelcast.config.MultiMapConfig;
import com.hazelcast.core.BaseMultiMap;
import com.hazelcast.core.EntryAdapter;
import com.hazelcast.core.EntryEvent;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.core.MultiMap;
import com.hazelcast.core.TransactionalMultiMap;
import com.hazelcast.test.AssertTask;
import com.hazelcast.test.HazelcastParallelClassRunner;
import com.hazelcast.test.HazelcastTestSupport;
import com.hazelcast.test.TestHazelcastInstanceFactory;
import com.hazelcast.test.annotation.ParallelTest;
import com.hazelcast.test.annotation.QuickTest;
import com.hazelcast.transaction.TransactionContext;
import com.hazelcast.transaction.TransactionException;
import com.hazelcast.transaction.TransactionNotActiveException;
import com.hazelcast.transaction.TransactionalTask;
import com.hazelcast.transaction.TransactionalTaskContext;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;
import java.util.Collection;
import java.util.concurrent.atomic.AtomicInteger;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
/**
* @author ali 4/5/13
*/
@RunWith(HazelcastParallelClassRunner.class)
@Category({QuickTest.class, ParallelTest.class})
public class TxnMultiMapTest extends HazelcastTestSupport {
@Test
public void testTxnCommit() throws TransactionException {
final TestHazelcastInstanceFactory factory = createHazelcastInstanceFactory(2);
final HazelcastInstance h1 = factory.newHazelcastInstance();
final HazelcastInstance h2 = factory.newHazelcastInstance();
final String map1 = "map1";
final String map2 = "map2";
final String key = "1";
boolean b = h1.executeTransaction(new TransactionalTask<Boolean>() {
public Boolean execute(TransactionalTaskContext context) throws TransactionException {
final TransactionalMultiMap<Object, Object> txMap1 = context.getMultiMap(map1);
final TransactionalMultiMap<Object, Object> txMap2 = context.getMultiMap(map2);
assertTrue(txMap1.put(key, "value1"));
Object value1 = getSingleValue(txMap1, key);
assertEquals("value1", value1);
assertTrue(txMap2.put(key, "value2"));
Object value2 = getSingleValue(txMap2, key);
assertEquals("value2", value2);
return true;
}
});
assertTrue(b);
assertEquals("value1", getSingleValue(h1.getMultiMap(map1), key));
assertEquals("value1", getSingleValue(h2.getMultiMap(map1), key));
assertEquals("value2", getSingleValue(h1.getMultiMap(map2), key));
assertEquals("value2", getSingleValue(h2.getMultiMap(map2), key));
}
private Object getSingleValue(BaseMultiMap multiMap, String key) {
Collection c = multiMap.get(key);
assertEquals(1, c.size());
return c.iterator().next();
}
@Test
public void testPutRemove() {
Config config = new Config();
final String name = "defMM";
config.getMultiMapConfig(name).setValueCollectionType(MultiMapConfig.ValueCollectionType.SET);
final int insCount = 4;
TestHazelcastInstanceFactory factory = createHazelcastInstanceFactory(insCount);
final HazelcastInstance[] instances = factory.newInstances(config);
TransactionContext context = instances[0].newTransactionContext();
try {
context.beginTransaction();
TransactionalMultiMap mm = context.getMultiMap(name);
assertEquals(0, mm.get("key1").size());
assertEquals(0, mm.valueCount("key1"));
assertTrue(mm.put("key1", "value1"));
assertFalse(mm.put("key1", "value1"));
assertEquals(1, mm.get("key1").size());
assertEquals(1, mm.valueCount("key1"));
assertFalse(mm.remove("key1", "value2"));
assertTrue(mm.remove("key1", "value1"));
assertFalse(mm.remove("key2", "value2"));
context.commitTransaction();
} catch (Exception e) {
fail(e.getMessage());
context.rollbackTransaction();
}
assertEquals(0, instances[1].getMultiMap(name).size());
assertTrue(instances[2].getMultiMap(name).put("key1", "value1"));
assertTrue(instances[2].getMultiMap(name).put("key2", "value2"));
}
@Test(expected = TransactionNotActiveException.class)
public void testTxnMultimapOuterTransaction() throws Throwable {
final HazelcastInstance h1 = createHazelcastInstance();
final TransactionContext transactionContext = h1.newTransactionContext();
transactionContext.beginTransaction();
TransactionalMultiMap<Object, Object> mm = transactionContext.getMultiMap("testTxnMultimapOuterTransaction");
mm.put("key", "value");
transactionContext.commitTransaction();
mm.get("key");
}
@Test
public void testListener() throws InterruptedException {
String mapName = "mm";
long key = 1L;
String value = "value";
String value2 = "value2";
final TestHazelcastInstanceFactory factory = createHazelcastInstanceFactory(2);
HazelcastInstance instance1 = factory.newHazelcastInstance();
HazelcastInstance instance2 = factory.newHazelcastInstance();
final CountingEntryListener<Object, Object> listener = new CountingEntryListener<Object, Object>();
MultiMap<Object, Object> map = instance1.getMultiMap(mapName);
map.addEntryListener(listener, true);
TransactionContext ctx1 = instance2.newTransactionContext();
ctx1.beginTransaction();
ctx1.getMultiMap(mapName).put(key, value);
ctx1.commitTransaction();
TransactionContext ctx2 = instance2.newTransactionContext();
ctx2.beginTransaction();
ctx2.getMultiMap(mapName).remove(key, value);
ctx2.commitTransaction();
TransactionContext ctx3 = instance2.newTransactionContext();
ctx3.beginTransaction();
ctx3.getMultiMap(mapName).put(key, value2);
ctx3.commitTransaction();
TransactionContext ctx4 = instance1.newTransactionContext();
ctx4.beginTransaction();
ctx4.getMultiMap(mapName).remove(key, value2);
ctx4.commitTransaction();
assertTrueEventually(new AssertTask() {
@Override
public void run()
throws Exception {
assertEquals(2, listener.getAddedCount());
assertEquals(2, listener.getRemovedCount());
}
});
}
private class CountingEntryListener<K, V> extends EntryAdapter<K, V> {
private final AtomicInteger addedCount = new AtomicInteger();
private final AtomicInteger removedCount = new AtomicInteger();
public void entryAdded(EntryEvent<K, V> event) {
addedCount.incrementAndGet();
}
public void entryRemoved(EntryEvent<K, V> event) {
removedCount.incrementAndGet();
}
public int getAddedCount() {
return addedCount.intValue();
}
public int getRemovedCount() {
return removedCount.intValue();
}
}
@Test
public void testIssue1276Lock() throws InterruptedException {
Long key = 1L;
Long value = 1L;
String mapName = "myMultimap";
final TestHazelcastInstanceFactory factory = createHazelcastInstanceFactory(2);
HazelcastInstance instance1 = factory.newHazelcastInstance();
HazelcastInstance instance2 = factory.newHazelcastInstance();
for (int i = 0; i < 2; i++) {
TransactionContext ctx1 = instance1.newTransactionContext();
ctx1.beginTransaction();
BaseMultiMap<Long, Long> txProfileTasks1 = ctx1.getMultiMap(mapName);
txProfileTasks1.put(key, value);
ctx1.commitTransaction();
TransactionContext ctx2 = instance2.newTransactionContext();
ctx2.beginTransaction();
BaseMultiMap<Long, Long> txProfileTasks2 = ctx2.getMultiMap(mapName);
txProfileTasks2.remove(key, value);
ctx2.commitTransaction();
}
}
}