/*
* JBoss, Home of Professional Open Source
* Copyright 2011 Red Hat Inc. and/or its affiliates and other
* contributors as indicated by the @author tags. All rights reserved.
* See the copyright.txt in the distribution for a full listing of
* individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.infinispan.atomic;
import java.util.Collection;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.transaction.TransactionManager;
import org.infinispan.Cache;
import org.infinispan.config.Configuration;
import org.infinispan.test.MultipleCacheManagersTest;
import org.infinispan.test.TestingUtil;
import org.infinispan.transaction.LockingMode;
import org.infinispan.transaction.TransactionMode;
import org.testng.annotations.Test;
/**
* @author Vladimir Blagojevic (C) 2011 Red Hat Inc.
* @author Sanne Grinovero (C) 2011 Red Hat Inc.
*/
@Test(groups = "functional", testName = "atomic.FineGrainedAtomicMapAPITest")
public class FineGrainedAtomicMapAPITest extends MultipleCacheManagersTest {
protected void createCacheManagers() throws Throwable {
Configuration c = getDefaultClusteredConfig(Configuration.CacheMode.REPL_SYNC, true)
.fluent()
.transaction()
.transactionMode(TransactionMode.TRANSACTIONAL)
.lockingMode(LockingMode.PESSIMISTIC)
.locking().lockAcquisitionTimeout(100l)
.build();
createClusteredCaches(2, "atomic", c);
}
@Test(enabled=true)
public void testMultipleTx() throws Exception{
final Cache<String, Object> cache1 = cache(0, "atomic");
final Cache<String, Object> cache2 = cache(1, "atomic");
final TransactionManager tm1 = TestingUtil.getTransactionManager(cache1);
final TransactionManager tm2 = TestingUtil.getTransactionManager(cache2);
final FineGrainedAtomicMap<String, String> map1 = AtomicMapLookup.getFineGrainedAtomicMap(cache1, "testMultipleTx", true);
final FineGrainedAtomicMap<String, String> map2 = AtomicMapLookup.getFineGrainedAtomicMap(cache2, "testMultipleTx", false);
assert map2.size() == 0 && map1.size() == 0;
tm1.begin();
map1.put("k1", "initial");
tm1.commit();
assert map2.size() == 1 && map1.size() == 1;
tm1.begin();
map1.put("k1", "v1");
map1.put("k2", "v2");
map1.put("k3", "v3");
tm1.commit();
assert map1.size() == 3;
assert map2.size() == 3;
tm1.begin();
map1.put("k4", "v4");
map1.put("k5", "v5");
map1.put("k6", "v6");
tm1.commit();
assert map2.get("k1").equals("v1");
assert map2.get("k2").equals("v2");
assert map2.get("k3").equals("v3");
assert map2.get("k4").equals("v4");
assert map2.get("k5").equals("v5");
assert map2.get("k6").equals("v6");
assert map1.get("k1").equals("v1");
assert map1.get("k2").equals("v2");
assert map1.get("k3").equals("v3");
assert map1.get("k4").equals("v4");
assert map1.get("k5").equals("v5");
assert map1.get("k6").equals("v6");
}
@Test(enabled=true)
public void testSizeOnCache() throws Exception {
final Cache<String, Object> cache1 = cache(0, "atomic");
assert cache1.size() == 0;
cache1.put("Hi", "Someone");
assert cache1.size() == 1;
tm(0, "atomic").begin();
assert cache1.size() == 1;
cache1.put("Need", "Read Consistency");
assert cache1.size() == 2;
tm(0, "atomic").commit();
assert cache1.size() == 2;
tm(0, "atomic").begin();
assert cache1.size() == 2;
cache1.put("Need Also", "Speed");
assert cache1.size() == 3;
tm(0, "atomic").rollback();
assert cache1.size() == 2;
FineGrainedAtomicMap<Object,Object> atomicMap = AtomicMapLookup.getFineGrainedAtomicMap(cache1, "testSizeOnCache", true);
assert cache1.size() == 3;
atomicMap.put("mm", "nn");
assert cache1.size() == 3;
tm(0, "atomic").begin();
assert cache1.size() == 3;
atomicMap = AtomicMapLookup.getFineGrainedAtomicMap(cache1, "testSizeOnCache-second", true);
assert cache1.size() == 4;
atomicMap.put("mm", "nn");
assert cache1.size() == 4 : "Cache size is actually " + cache1.size();
tm(0, "atomic").commit();
assert cache1.size() == 4;
tm(0, "atomic").begin();
assert cache1.size() == 4;
atomicMap = AtomicMapLookup.getFineGrainedAtomicMap(cache1, "testSizeOnCache-third", true);
assert cache1.size() == 5;
atomicMap.put("mm", "nn");
assert cache1.size() == 5 : "Cache size is actually " + cache1.size();
atomicMap.put("ooo", "weird!");
assert cache1.size() == 5 : "Cache size is actually " + cache1.size();
atomicMap = AtomicMapLookup.getFineGrainedAtomicMap(cache1, "testSizeOnCache-onemore", true);
assert cache1.size() == 6 : "Cache size is actually " + cache1.size();
atomicMap.put("even less?", "weird!");
assert cache1.size() == 6 : "Cache size is actually " + cache1.size();
tm(0, "atomic").rollback();
assert cache1.size() == 4;
}
@Test(enabled=true)
public void testConcurrentReadsOnExistingMap() throws Exception {
final Cache<String, Object> cache1 = cache(0, "atomic");
assert cache1.size() == 0;
final FineGrainedAtomicMap<String, String> map = AtomicMapLookup.getFineGrainedAtomicMap(cache1, "testConcurrentReadsOnExistingMap", true);
map.put("the-1", "my preciousss");
tm(0, "atomic").begin();
assert "my preciousss".equals(map.get("the-1"));
final AtomicBoolean allok = new AtomicBoolean(false);
map.put("the-2", "a minor");
fork(new Runnable() {
@Override
public void run() {
try {
tm(0, "atomic").begin();
FineGrainedAtomicMap<String, String> map = AtomicMapLookup.getFineGrainedAtomicMap(cache1, "testConcurrentReadsOnExistingMap", true);
assert "my preciousss".equals(map.get("the-1"));
assert ! map.containsKey("the-2");
tm(0, "atomic").commit();
allok.set(true);
} catch (Exception e) {
log.error("Unexpected error performing transaction", e);
}
}
}, true);
tm(0, "atomic").commit();
assert allok.get();
}
@Test(enabled=true)
public void testConcurrentWritesOnExistingMap() throws Exception {
final Cache<String, Object> cache1 = cache(0, "atomic");
assert cache1.size() == 0;
final FineGrainedAtomicMap<String, String> map = AtomicMapLookup.getFineGrainedAtomicMap(cache1, "testConcurrentReadsOnExistingMap", true);
map.put("the-1", "my preciousss");
tm(0, "atomic").begin();
assert "my preciousss".equals(map.get("the-1"));
final AtomicBoolean allok = new AtomicBoolean(false);
map.put("the-2", "a minor");
fork(new Runnable() {
@Override
public void run() {
try {
tm(0, "atomic").begin();
FineGrainedAtomicMap<String, String> map = AtomicMapLookup.getFineGrainedAtomicMap(cache1, "testConcurrentReadsOnExistingMap", true);
assert "my preciousss".equals(map.get("the-1"));
assert ! map.containsKey("the-2");
map.put("the-2", "a minor-different"); // We're in pessimistic locking, so this put is going to block
tm(0, "atomic").commit();
} catch (org.infinispan.util.concurrent.TimeoutException e) {
allok.set(true);
} catch (Exception e) {
log.error("Unexpected error performing transaction", e);
}
}
}, true);
tm(0, "atomic").commit();
assert allok.get();
}
@Test(enabled=true)
public void testConcurrentWritesAndIteration() throws Exception {
final Cache<String, Object> cache1 = cache(0, "atomic");
assert cache1.size() == 0;
FineGrainedAtomicMap<String, String> map = AtomicMapLookup.getFineGrainedAtomicMap(cache1, "testConcurrentWritesAndIteration", true);
assert map.size() == 0;
final AtomicBoolean allOk = new AtomicBoolean(true);
final CountDownLatch latch = new CountDownLatch(1);
Thread t1 = fork(new Runnable() {
@Override
public void run() {
try {
FineGrainedAtomicMap<String, String> map = AtomicMapLookup.getFineGrainedAtomicMap(cache1, "testConcurrentWritesAndIteration", true);
latch.await();
for(int i = 0; i< 500; i++){
map.put("key-" + i, "value-" + i);
}
} catch (Exception e) {
log.error("Unexpected error performing transaction", e);
}
}
}, false);
Thread t2 = fork(new Runnable() {
@Override
public void run() {
FineGrainedAtomicMap<String, String> map = AtomicMapLookup.getFineGrainedAtomicMap(cache1, "testConcurrentWritesAndIteration", true);
try {
latch.await();
for(int i = 0; i< 500; i++){
map.keySet();
}
} catch (Exception e) {
allOk.set(false);
log.error("Unexpected error performing transaction", e);
}
}
}, false);
latch.countDown();
t1.join();
t2.join();
assert allOk.get() : "iteration raised an exception";
}
@Test(enabled=true)
public void testRollback() throws Exception {
final Cache<String, Object> cache1 = cache(0, "atomic");
final Cache<String, Object> cache2 = cache(1, "atomic");
final FineGrainedAtomicMap<String, String> map1 = AtomicMapLookup.getFineGrainedAtomicMap(cache1, "testRollback", true);
tm(0, "atomic").begin();
map1.put("k1", "v");
map1.put("k2", "v2");
tm(0, "atomic").rollback();
FineGrainedAtomicMap<Object, Object> instance = AtomicMapLookup.getFineGrainedAtomicMap(cache2, "testRollback", true);
assert !instance.containsKey("k1");
assert !map1.containsKey("k1");
}
@Test(enabled=true,expectedExceptions={IllegalArgumentException.class})
public void testFineGrainedMapAfterSimpleMap() throws Exception {
Cache<String, Object> cache1 = cache(0, "atomic");
AtomicMap<String, String> map = AtomicMapLookup.getAtomicMap(cache1, "testReplicationRemoveCommit");
FineGrainedAtomicMap<String, String> map2 = AtomicMapLookup.getFineGrainedAtomicMap(cache1, "testReplicationRemoveCommit");
}
@Test(enabled=true)
public void testRollbackAndThenCommit() throws Exception {
final Cache<String, Object> cache1 = cache(0, "atomic");
final Cache<String, Object> cache2 = cache(1, "atomic");
final FineGrainedAtomicMap<String, String> map1 = AtomicMapLookup.getFineGrainedAtomicMap(cache1, "testRollbackAndThenCommit", true);
tm(0, "atomic").begin();
map1.put("k1", "v");
map1.put("k2", "v2");
tm(0, "atomic").rollback();
FineGrainedAtomicMap<Object, Object> map2 = AtomicMapLookup.getFineGrainedAtomicMap(cache2, "testRollbackAndThenCommit", true);
assert !map2.containsKey("k1");
assert !map1.containsKey("k1");
tm(0, "atomic").begin();
map1.put("k3", "v3");
map1.put("k4", "v4");
tm(0, "atomic").commit();
assert map1.size() == 2 && map2.size() == 2;
}
@Test(enabled=true)
public void testCreateMapInTx() throws Exception {
final Cache<String, Object> cache1 = cache(0, "atomic");
final Cache<String, Object> cache2 = cache(1, "atomic");
FineGrainedAtomicMap<String, String> map1;
tm(0, "atomic").begin();
map1 = AtomicMapLookup.getFineGrainedAtomicMap(cache1, "testCreateMapInTx", true);
map1.put("k1", "v1");
tm(0, "atomic").commit();
assert map1.size() == 1;
assert map1.get("k1").equals("v1");
final FineGrainedAtomicMap<String, String> map2 = AtomicMapLookup.getFineGrainedAtomicMap(cache2, "testCreateMapInTx", true);
assert map2.size() == 1;
assert map2.get("k1").equals("v1");
}
@Test(enabled=true)
public void testNoTx() throws Exception {
final Cache<String, Object> cache1 = cache(0, "atomic");
final Cache<String, Object> cache2 = cache(1, "atomic");
final FineGrainedAtomicMap<String, String> map = AtomicMapLookup.getFineGrainedAtomicMap(cache1, "testNoTx", true);
map.put("existing", "existing");
map.put("blah", "blah");
assert map.size() == 2;
assert map.get("blah").equals("blah");
assert map.containsKey("existing");
}
@Test(enabled=true)
public void testReadUncommittedValues() throws Exception {
Cache<String, Object> cache1 = cache(0, "atomic");
Cache<String, Object> cache2 = cache(1, "atomic");
FineGrainedAtomicMap<String, String> map = AtomicMapLookup.getFineGrainedAtomicMap(cache1, "testReadUncommittedValues");
TestingUtil.getTransactionManager(cache1).begin();
map.put("key one", "value one");
map.put("blah", "blah");
assert "value one".equals(map.get("key one"));
assert map.size() == 2;
assert map.keySet().size() == 2;
Set<String> keySet = map.keySet();
for (String k : keySet) {
assert k.equals("key one") || k.equals("blah");
}
Collection<String> values = map.values();
for (String v : values) {
assert v.equals("value one") || v.equals("blah");
}
assert map.containsKey("key one");
assert map.values().size() == 2;
assert !map.isEmpty();
Set<Entry<String,String>> entrySet = map.entrySet();
for (Entry<String, String> entry : entrySet) {
if(entry.getKey().equals("key one")) assert entry.getValue().equals("value one");
if(entry.getKey().equals("blah")) assert entry.getValue().equals("blah");
}
FineGrainedAtomicMap<String, String> sameAsMap = AtomicMapLookup.getFineGrainedAtomicMap(cache1, "testReadUncommittedValues");
assert "value one".equals(sameAsMap.get("key one"));
TestingUtil.getTransactionManager(cache1).commit();
assert map.size() == 2;
assert map.get("blah").equals("blah");
}
@Test(enabled=true)
public void testCommitReadUncommittedValues() throws Exception {
Cache<String, Object> cache1 = cache(0, "atomic");
Cache<String, Object> cache2 = cache(1, "atomic");
FineGrainedAtomicMap<String, String> map = AtomicMapLookup.getFineGrainedAtomicMap(cache1, "testCommitReadUncommittedValues");
TestingUtil.getTransactionManager(cache1).begin();
map.put("existing", "existing");
map.put("hey", "blah");
TestingUtil.getTransactionManager(cache1).commit();
TestingUtil.getTransactionManager(cache1).begin();
map.put("key one", "value one");
map.put("blah", "toronto");
assert "value one".equals(map.get("key one"));
assert map.size() == 4;
assert map.keySet().size() == 4;
Set<String> keySet = map.keySet();
for (String k : keySet) {
assert k.equals("key one") || k.equals("blah") || k.equals("existing") || k.equals("hey");
}
Collection<String> values = map.values();
for (String v : values) {
assert v.equals("value one") || v.equals("blah") || v.equals("existing") || v.equals("toronto");
}
assert map.containsKey("key one");
assert map.values().size() == 4;
assert !map.isEmpty();
Set<Entry<String,String>> entrySet = map.entrySet();
for (Entry<String, String> entry : entrySet) {
if(entry.getKey().equals("key one")) assert entry.getValue().equals("value one");
if(entry.getKey().equals("blah")) assert entry.getValue().equals("toronto");
if(entry.getKey().equals("existing")) assert entry.getValue().equals("existing");
if(entry.getKey().equals("hey")) assert entry.getValue().equals("blah");
}
FineGrainedAtomicMap<String, String> sameAsMap = AtomicMapLookup.getFineGrainedAtomicMap(cache1, "testCommitReadUncommittedValues");
assert "value one".equals(sameAsMap.get("key one"));
TestingUtil.getTransactionManager(cache1).commit();
assert map.size() == 4;
assert map.get("blah").equals("toronto");
}
@Test(enabled=true)
public void testConcurrentTx() throws Exception {
final Cache<String, Object> cache1 = cache(0, "atomic");
final Cache<String, Object> cache2 = cache(1, "atomic");
final TransactionManager tm1 = TestingUtil.getTransactionManager(cache1);
final TransactionManager tm2 = TestingUtil.getTransactionManager(cache2);
final FineGrainedAtomicMap<String, String> map1 = AtomicMapLookup.getFineGrainedAtomicMap(cache1, "testConcurrentTx",true);
tm1.begin();
map1.put("k1", "initial");
tm1.commit();
final FineGrainedAtomicMap<String, String> map2 = AtomicMapLookup.getFineGrainedAtomicMap(cache2, "testConcurrentTx", false);
assert map2.size() == 1 && map1.size() == 1;
Thread t1 = new Thread( new Runnable() {
@Override
public void run() {
try {
tm1.begin();
map1.put("k1", "tx1Value");
tm1.commit();
}
catch (Exception e) {
log.error(e);
}
}});
t1.start();
Thread t2 = new Thread(new Runnable(){
@Override
public void run() {
try {
tm2.begin();
map2.put("k2", "tx2Value");
tm2.commit();
}
catch (Exception e) {
log.error(e);
}
}});
t2.start();
t2.join();
t1.join();
assert map2.get("k2").equals("tx2Value");
assert map2.get("k1").equals("tx1Value");
assert map1.get("k2").equals("tx2Value");
assert map1.get("k1").equals("tx1Value");
}
@Test(enabled=true)
public void testReplicationPutCommit() throws Exception {
Cache<String, Object> cache1 = cache(0, "atomic");
Cache<String, Object> cache2 = cache(1, "atomic");
FineGrainedAtomicMap<String, String> map = AtomicMapLookup.getFineGrainedAtomicMap(cache1, "testReplicationPutCommit");
TestingUtil.getTransactionManager(cache1).begin();
map.put("existing", "existing");
map.put("blah", "blah");
TestingUtil.getTransactionManager(cache1).commit();
assert map.size() == 2;
assert map.get("blah").equals("blah");
assert map.containsKey("existing");
FineGrainedAtomicMap<Object, Object> other = AtomicMapLookup.getFineGrainedAtomicMap(cache2, "testReplicationPutCommit", false);
assert other.size() == 2:" no, other size is " + other.size();
assert other.get("blah").equals("blah");
assert other.containsKey("blah");
//ok, do another tx with delta changes
TestingUtil.getTransactionManager(cache2).begin();
other.put("existing", "not existing");
other.put("not existing", "peace on Earth");
TestingUtil.getTransactionManager(cache2).commit();
assert map.size() == 3;
assert map.get("blah").equals("blah");
assert map.get("existing").equals("not existing");
assert map.get("not existing").equals("peace on Earth");
assert other.size() == 3;
assert other.get("blah").equals("blah");
assert other.get("existing").equals("not existing");
assert other.get("not existing").equals("peace on Earth");
}
@Test(enabled=true)
public void testReplicationRemoveCommit() throws Exception {
Cache<String, Object> cache1 = cache(0, "atomic");
Cache<String, Object> cache2 = cache(1, "atomic");
FineGrainedAtomicMap<String, String> map = AtomicMapLookup.getFineGrainedAtomicMap(cache1, "testReplicationRemoveCommit");
TestingUtil.getTransactionManager(cache1).begin();
map.put("existing", "existing");
map.put("blah", "blah");
TestingUtil.getTransactionManager(cache1).commit();
assert map.size() == 2;
assert map.get("blah").equals("blah");
assert map.containsKey("existing");
FineGrainedAtomicMap<Object, Object> other = AtomicMapLookup.getFineGrainedAtomicMap(cache2, "testReplicationRemoveCommit", false);
assert other.size() == 2:" no, other size is " + other.size();
assert other.get("blah").equals("blah");
assert other.containsKey("blah");
//ok, do another tx with delta changes
TestingUtil.getTransactionManager(cache2).begin();
String removed = map.remove("existing");
assert removed.equals("existing");
TestingUtil.getTransactionManager(cache2).commit();
assert map.size() == 1;
assert map.get("blah").equals("blah");
assert other.size() == 1;
assert other.get("blah").equals("blah");
}
@Test(enabled=true)
public void testReplicationPutAndClearCommit() throws Exception {
Cache<String, Object> cache1 = cache(0, "atomic");
Cache<String, Object> cache2 = cache(1, "atomic");
FineGrainedAtomicMap<String, String> map = AtomicMapLookup.getFineGrainedAtomicMap(cache1, "map");
FineGrainedAtomicMap<String, String> map2 = AtomicMapLookup.getFineGrainedAtomicMap(cache2, "map", false);
TestingUtil.getTransactionManager(cache1).begin();
map.put("existing", "existing");
map.put("blah", "blah");
map.size();
TestingUtil.getTransactionManager(cache1).commit();
assert map.size() == 2;
assert map2.size() == 2;
//ok, do another tx with clear delta changes
TestingUtil.getTransactionManager(cache2).begin();
map2.clear();
TestingUtil.getTransactionManager(cache2).commit();
assert map.size() == 0;
assert map2.size() == 0;
}
}