/*
* Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Florent Guillaume
*/
package org.eclipse.ecr.core.storage.sql;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.ecr.core.api.CoreSession;
import org.eclipse.ecr.core.api.security.SecurityConstants;
import org.eclipse.ecr.core.storage.sql.testlib.TXSQLRepositoryTestCase;
import org.eclipse.ecr.runtime.jtajca.NuxeoContainer;
import org.eclipse.ecr.runtime.jtajca.NuxeoContainer.ConnectionManagerConfiguration;
import org.eclipse.ecr.runtime.jtajca.NuxeoContainer.TransactionManagerConfiguration;
import org.eclipse.ecr.runtime.transaction.TransactionHelper;
/**
* Test JTAJCA pool behavior.
*/
public class TestJCAPoolBehavior extends TXSQLRepositoryTestCase {
private static final Log log = LogFactory.getLog(TestJCAPoolBehavior.class);
public static final int MIN_POOL_SIZE = 2;
public static final int MAX_POOL_SIZE = 5;
public static final int BLOCKING_TIMEOUT = 200;
public volatile Exception threadException;
@Override
protected void setUpContainer() throws Exception {
TransactionManagerConfiguration tmconfig = new TransactionManagerConfiguration();
ConnectionManagerConfiguration cmconfig = new ConnectionManagerConfiguration();
cmconfig.setMinPoolSize(MIN_POOL_SIZE);
cmconfig.setMaxPoolSize(MAX_POOL_SIZE);
cmconfig.setBlockingTimeoutMillis(BLOCKING_TIMEOUT);
NuxeoContainer.install(tmconfig, cmconfig);
}
public void testOpenAllConnections() throws Exception {
if (!hasPoolingConfig()) {
return;
}
threadException = null;
// main thread already uses 1 session
Thread[] threads = new Thread[MAX_POOL_SIZE - 1];
for (int i = 0; i < threads.length; i++) {
threads[i] = new Thread(new SessionHolder(2000));
threads[i].start();
}
Thread.sleep(500);
assertNull(threadException);
// finish all threads
for (int i = 0; i < threads.length; i++) {
threads[i].join();
}
assertNull(threadException);
}
public void testOpenMoreConnectionsThanMax() throws Exception {
if (!hasPoolingConfig()) {
return;
}
threadException = null;
// main thread already uses 1 session
Thread[] threads = new Thread[MAX_POOL_SIZE - 1];
for (int i = 0; i < threads.length; i++) {
threads[i] = new Thread(new SessionHolder(2000));
threads[i].start();
}
Thread.sleep(500);
assertNull(threadException);
// all connections are used, but try yet another one
Thread t = new Thread(new SessionHolder(2000));
t.start();
Thread.sleep(BLOCKING_TIMEOUT + 500);
assertNotNull(threadException);
threadException = null;
// finish all threads
for (int i = 0; i < threads.length; i++) {
threads[i].join();
}
assertNull(threadException);
// re-test full threads use
testOpenAllConnections();
}
/** Creates a session and holds it open for a while. */
public class SessionHolder implements Runnable {
public final int sleepMillis;
public SessionHolder(int sleepMillis) {
this.sleepMillis = sleepMillis;
}
@Override
public void run() {
log.info("start of thread " + Thread.currentThread().getName());
try {
TransactionHelper.startTransaction();
CoreSession s = null;
try {
s = openSessionAs(SecurityConstants.ADMINISTRATOR);
Thread.sleep(sleepMillis);
} finally {
if (s != null) {
closeSession(s);
}
TransactionHelper.commitOrRollbackTransaction();
}
} catch (Exception e) {
// log.error(e, e);
if (threadException == null) {
threadException = e;
}
}
log.info("end of thread " + Thread.currentThread().getName());
}
}
}