/* * 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.replication; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicBoolean; import org.infinispan.AdvancedCache; import org.infinispan.context.Flag; import org.infinispan.distribution.BaseDistFunctionalTest; import org.infinispan.transaction.LockingMode; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; /** * Verifies the Flags affect both local and remote nodes. * * @author Sanne Grinovero <sanne@hibernate.org> (C) 2011 Red Hat Inc. * @since 4.2.1 */ @Test(groups = "functional", testName = FlagsReplicationTest.TEST_NAME) public class FlagsReplicationTest extends BaseDistFunctionalTest { static final String TEST_NAME = "replication.FlagsReplicationTest"; static final String DATA_PROVIDER = TEST_NAME + ".dataprovider"; private ExecutorService threadPool; private final Integer one = 1; private final String key = TEST_NAME; public FlagsReplicationTest() { tx = true; cacheName = TEST_NAME; cleanup = CleanupPhase.AFTER_METHOD; lockingMode = LockingMode.PESSIMISTIC; lockTimeout = 1; } @DataProvider(name = DATA_PROVIDER) public Object[][] createTestConfigurations() { return new Object[][] { { true, true }, { false, false }, { false, true }, { true, false }, }; } @Test(dataProvider = DATA_PROVIDER) public void testScenario(boolean cache1IsOwner, boolean cache2IsOwner) throws Throwable { log.tracef("Start cache1IsOwner = %s, cache2IsOwner %s", cache1IsOwner, cache2IsOwner); AdvancedCache cache1 = (cache1IsOwner ? getFirstOwner(key) : getFirstNonOwner(key)).getAdvancedCache(); AdvancedCache cache2 = (cache2IsOwner ? getFirstOwner(key) : getFirstNonOwner(key)).getAdvancedCache(); assert null == cache1.put(key, one); haveSecondaryThreadTakeLock(cache2); cache1.getTransactionManager().begin(); boolean locked = cache1.withFlags(Flag.ZERO_LOCK_ACQUISITION_TIMEOUT, Flag.FAIL_SILENTLY).lock(key); assert !locked; Object removed = cache1.withFlags(Flag.SKIP_LOCKING).remove(key); assert one.equals(removed); haveSecondaryThreadReleaseLock(cache2); cache1.getTransactionManager().commit(); assert null == cache2.get(key); log.tracef("End cache1IsOwner = %s, cache2IsOwner %s", cache1IsOwner, cache2IsOwner); } private void haveSecondaryThreadTakeLock(final AdvancedCache viaCache) throws InterruptedException, ExecutionException { AtomicBoolean noerrors = new AtomicBoolean(true); Future<?> submit = threadPool.submit(new LockingThread(viaCache, noerrors)); submit.get(); //wait to be done assert noerrors.get(); } private void haveSecondaryThreadReleaseLock(final AdvancedCache viaCache) throws InterruptedException, ExecutionException { AtomicBoolean noerrors = new AtomicBoolean(true); Future<?> submit = threadPool.submit(new CommitThread(viaCache, noerrors)); submit.get(); //wait to be done assert noerrors.get(); } private class LockingThread implements Runnable { private final AdvancedCache cache; private final AtomicBoolean allok; LockingThread(AdvancedCache cache, AtomicBoolean allok) { this.cache = cache; this.allok = allok; } @Override public void run() { try { log.trace("About to try to acquire a lock."); cache.getTransactionManager().begin(); if (! cache.lock(key)) { allok.set(false); log.trace("Could not acquire lock"); } } catch (Throwable e) { log.trace("Error", e); allok.set(false); } } } static private class CommitThread implements Runnable { private final AdvancedCache cache; private final AtomicBoolean allok; CommitThread(AdvancedCache cache, AtomicBoolean allok) { this.cache = cache; this.allok = allok; } @Override public void run() { try { cache.getTransactionManager().commit(); } catch (Throwable e) { allok.set(false); } } } @BeforeClass(alwaysRun = true) protected void startThreadPool() { threadPool = Executors.newFixedThreadPool(1); } @AfterClass(alwaysRun = true) protected void stopThreadPool() { threadPool.shutdownNow(); } }