package org.infinispan.lucene.readlocks;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import org.infinispan.Cache;
import org.infinispan.configuration.cache.ConfigurationBuilder;
import org.infinispan.lucene.CacheTestSupport;
import org.infinispan.lucene.FileCacheKey;
import org.infinispan.lucene.FileMetadata;
import org.infinispan.manager.EmbeddedCacheManager;
import org.infinispan.test.SingleCacheManagerTest;
import org.infinispan.test.fwk.TestCacheManagerFactory;
import org.testng.AssertJUnit;
import org.testng.annotations.Test;
/**
* Stress test for {@link org.infinispan.lucene.readlocks.LocalLockMergingSegmentReadLocker}. See also ISPN-4497 for an
* example of race conditions it protects against.
*
* @author Sanne Grinovero
* @since 7.0
*/
@Test(groups = "profiling", testName = "lucene.readlocks.LocalLockStressTest")
public class LocalLockStressTest extends SingleCacheManagerTest {
static final int NUM_THREADS = 10;
static final int TEST_MINUTES_MAX = 10;
@Override
protected EmbeddedCacheManager createCacheManager() throws Exception {
ConfigurationBuilder configurationBuilder = CacheTestSupport.createLocalCacheConfiguration();
return TestCacheManagerFactory.createCacheManager(configurationBuilder);
}
@Test
public void testMultiThreaded() {
final Cache<Object, Object> metadata = cacheManager.getCache("metadata");
final Cache<Object, Object> chunks = cacheManager.getCache("chunks");
final Cache<Object, Integer> locks = cacheManager.getCache("locks");
FileMetadata fileMetadata = new FileMetadata(10);
fileMetadata.setSize(11); // Make it chunked otherwise no read lock will involved
metadata.put(new FileCacheKey("indexName", "fileName", -1), fileMetadata);
final LocalLockMergingSegmentReadLocker locker = new LocalLockMergingSegmentReadLocker(locks, chunks, metadata, "indexName", -1);
final AtomicBoolean testFailed = new AtomicBoolean(false);
final ExecutorService exec = Executors.newFixedThreadPool(NUM_THREADS);
Runnable stressor = new Runnable() {
@Override
public void run() {
try {
int counter = 0;
while (testFailed.get() == false) {
locker.acquireReadLock("fileName");
Thread.sleep(2);
locker.deleteOrReleaseReadLock("fileName");
// Take a break every now and a again to try and avoid the same LocalReadLock being used constantly
if (counter++ % 900 == 0) {
System.out.print(".");
Thread.sleep(7);
}
if (metadata.get(new FileCacheKey("indexName", "fileName", -1)) == null) {
//Shouldn't have been deleted!
testFailed.set(true);
System.out.print("X");
}
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return;
}
}
};
for (int i = 0; i < NUM_THREADS; i++) {
exec.execute(stressor);
}
System.out.println("Stressor threads started...");
exec.shutdown();
try {
exec.awaitTermination(TEST_MINUTES_MAX, TimeUnit.MINUTES);
} catch (InterruptedException e) {
exec.shutdownNow();
}
AssertJUnit.assertFalse(testFailed.get());
}
}