Lines 24-35
Link Here
|
24 |
import java.util.Map; |
24 |
import java.util.Map; |
25 |
import java.util.Set; |
25 |
import java.util.Set; |
26 |
|
26 |
|
27 |
import org.apache.avalon.excalibur.datasource.DataSourceComponent; |
|
|
28 |
import org.apache.avalon.excalibur.datasource.ResourceLimitingJdbcDataSource; |
29 |
import org.apache.avalon.framework.configuration.Configuration; |
30 |
import org.apache.avalon.framework.configuration.ConfigurationException; |
31 |
import org.apache.avalon.framework.configuration.DefaultConfiguration; |
32 |
import org.apache.avalon.framework.logger.LogKitLogger; |
33 |
import org.apache.jmeter.config.ConfigElement; |
27 |
import org.apache.jmeter.config.ConfigElement; |
34 |
import org.apache.jmeter.testbeans.TestBean; |
28 |
import org.apache.jmeter.testbeans.TestBean; |
35 |
import org.apache.jmeter.testbeans.TestBeanHelper; |
29 |
import org.apache.jmeter.testbeans.TestBeanHelper; |
Lines 40-67
Link Here
|
40 |
import org.apache.jorphan.logging.LoggingManager; |
34 |
import org.apache.jorphan.logging.LoggingManager; |
41 |
import org.apache.jorphan.util.JOrphanUtils; |
35 |
import org.apache.jorphan.util.JOrphanUtils; |
42 |
import org.apache.log.Logger; |
36 |
import org.apache.log.Logger; |
|
|
37 |
import org.apache.tomcat.jdbc.pool.DataSource; |
38 |
import org.apache.tomcat.jdbc.pool.DataSourceProxy; |
39 |
import org.apache.tomcat.jdbc.pool.PoolProperties; |
43 |
|
40 |
|
44 |
public class DataSourceElement extends AbstractTestElement |
41 |
public class DataSourceElement extends AbstractTestElement |
45 |
implements ConfigElement, TestStateListener, TestBean |
42 |
implements ConfigElement, TestStateListener, TestBean { |
46 |
{ |
|
|
47 |
private static final Logger log = LoggingManager.getLoggerForClass(); |
43 |
private static final Logger log = LoggingManager.getLoggerForClass(); |
48 |
|
44 |
|
49 |
private static final long serialVersionUID = 233L; |
45 |
private static final long serialVersionUID = 234L; |
50 |
|
46 |
|
51 |
private transient String dataSource, driver, dbUrl, username, password, checkQuery, poolMax, connectionAge, timeout, |
47 |
private transient String dataSource; |
52 |
trimInterval,transactionIsolation; |
48 |
private transient String driver; |
|
|
49 |
private transient String dbUrl; |
50 |
private transient String username; |
51 |
private transient String password; |
52 |
private transient String checkQuery; |
53 |
private transient String poolMax; |
54 |
private transient String connectionAge; |
55 |
private transient String timeout; |
56 |
private transient String trimInterval; |
57 |
private transient String transactionIsolation; |
53 |
|
58 |
|
54 |
private transient boolean keepAlive, autocommit; |
59 |
private transient boolean keepAlive; |
|
|
60 |
private transient boolean autocommit; |
55 |
|
61 |
|
56 |
/* |
62 |
/* |
57 |
* The datasource is set up by testStarted and cleared by testEnded. |
63 |
* The datasource is set up by testStarted and cleared by testEnded. |
58 |
* These are called from different threads, so access must be synchronized. |
64 |
* These are called from different threads, so access must be synchronized. |
59 |
* The same instance is called in each case. |
65 |
* The same instance is called in each case. |
60 |
*/ |
66 |
*/ |
61 |
private transient ResourceLimitingJdbcDataSource excaliburSource; |
67 |
private transient DataSource tomcatPoolDataSource; |
62 |
|
68 |
|
63 |
// Keep a record of the pre-thread pools so that they can be disposed of at the end of a test |
69 |
// Keep a record of the pre-thread pools so that they can be disposed of at the end of a test |
64 |
private transient Set<ResourceLimitingJdbcDataSource> perThreadPoolSet; |
70 |
private transient Set<DataSource> perThreadPoolSet; |
65 |
|
71 |
|
66 |
public DataSourceElement() { |
72 |
public DataSourceElement() { |
67 |
} |
73 |
} |
Lines 69-83
Link Here
|
69 |
@Override |
75 |
@Override |
70 |
public void testEnded() { |
76 |
public void testEnded() { |
71 |
synchronized (this) { |
77 |
synchronized (this) { |
72 |
if (excaliburSource != null) { |
78 |
if (tomcatPoolDataSource != null) { |
73 |
excaliburSource.dispose(); |
79 |
tomcatPoolDataSource.close(true); |
74 |
} |
80 |
} |
75 |
excaliburSource = null; |
81 |
tomcatPoolDataSource = null; |
76 |
} |
82 |
} |
77 |
if (perThreadPoolSet != null) {// in case |
83 |
if (perThreadPoolSet != null) {// in case |
78 |
for(ResourceLimitingJdbcDataSource dsc : perThreadPoolSet){ |
84 |
for(DataSource dsc : perThreadPoolSet){ |
79 |
log.debug("Disposing pool: "+dsc.getInstrumentableName()+" @"+System.identityHashCode(dsc)); |
85 |
log.debug("Closing pool: "+dsc.getName()+" @"+System.identityHashCode(dsc)); |
80 |
dsc.dispose(); |
86 |
dsc.close(true); |
81 |
} |
87 |
} |
82 |
perThreadPoolSet=null; |
88 |
perThreadPoolSet=null; |
83 |
} |
89 |
} |
Lines 100-113
Link Here
|
100 |
log.error("JDBC data source already defined for: "+poolName); |
106 |
log.error("JDBC data source already defined for: "+poolName); |
101 |
} else { |
107 |
} else { |
102 |
String maxPool = getPoolMax(); |
108 |
String maxPool = getPoolMax(); |
103 |
perThreadPoolSet = Collections.synchronizedSet(new HashSet<ResourceLimitingJdbcDataSource>()); |
109 |
perThreadPoolSet = Collections.synchronizedSet(new HashSet<DataSource>()); |
104 |
if (maxPool.equals("0")){ // i.e. if we want per thread pooling |
110 |
if (maxPool.equals("0")){ // i.e. if we want per thread pooling |
105 |
variables.putObject(poolName, new DataSourceComponentImpl()); // pool will be created later |
111 |
variables.putObject(poolName, new DataSourceComponentImpl()); // pool will be created later |
106 |
} else { |
112 |
} else { |
107 |
ResourceLimitingJdbcDataSource src=initPool(maxPool); |
113 |
DataSource src=initPool(maxPool); |
108 |
synchronized(this){ |
114 |
synchronized(this){ |
109 |
excaliburSource = src; |
115 |
tomcatPoolDataSource = src; |
110 |
variables.putObject(poolName, new DataSourceComponentImpl(excaliburSource)); |
116 |
variables.putObject(poolName, new DataSourceComponentImpl(tomcatPoolDataSource)); |
111 |
} |
117 |
} |
112 |
} |
118 |
} |
113 |
} |
119 |
} |
Lines 122-128
Link Here
|
122 |
public Object clone() { |
128 |
public Object clone() { |
123 |
DataSourceElement el = (DataSourceElement) super.clone(); |
129 |
DataSourceElement el = (DataSourceElement) super.clone(); |
124 |
synchronized (this) { |
130 |
synchronized (this) { |
125 |
el.excaliburSource = excaliburSource; |
131 |
el.tomcatPoolDataSource = tomcatPoolDataSource; |
126 |
el.perThreadPoolSet = perThreadPoolSet; |
132 |
el.perThreadPoolSet = perThreadPoolSet; |
127 |
} |
133 |
} |
128 |
return el; |
134 |
return el; |
Lines 140-147
Link Here
|
140 |
if (poolObject == null) { |
146 |
if (poolObject == null) { |
141 |
throw new SQLException("No pool found named: '" + poolName + "', ensure Variable Name matches Variable Name of JDBC Connection Configuration"); |
147 |
throw new SQLException("No pool found named: '" + poolName + "', ensure Variable Name matches Variable Name of JDBC Connection Configuration"); |
142 |
} else { |
148 |
} else { |
143 |
if(poolObject instanceof DataSourceComponent) { |
149 |
if(poolObject instanceof DataSourceProxy) { |
144 |
DataSourceComponent pool = (DataSourceComponent) poolObject; |
150 |
DataSourceProxy pool = (DataSourceProxy) poolObject; |
145 |
return pool.getConnection(); |
151 |
return pool.getConnection(); |
146 |
} else { |
152 |
} else { |
147 |
String errorMsg = "Found object stored under variable:'"+poolName |
153 |
String errorMsg = "Found object stored under variable:'"+poolName |
Lines 156-165
Link Here
|
156 |
* Set up the DataSource - maxPool is a parameter, so the same code can |
162 |
* Set up the DataSource - maxPool is a parameter, so the same code can |
157 |
* also be used for setting up the per-thread pools. |
163 |
* also be used for setting up the per-thread pools. |
158 |
*/ |
164 |
*/ |
159 |
private ResourceLimitingJdbcDataSource initPool(String maxPool) { |
165 |
private DataSource initPool(String maxPool) { |
160 |
ResourceLimitingJdbcDataSource source = null; |
166 |
PoolProperties poolProperties = new PoolProperties(); |
161 |
source = new ResourceLimitingJdbcDataSource(); |
|
|
162 |
DefaultConfiguration config = new DefaultConfiguration("rl-jdbc"); // $NON-NLS-1$ |
163 |
|
167 |
|
164 |
if (log.isDebugEnabled()) { |
168 |
if (log.isDebugEnabled()) { |
165 |
StringBuilder sb = new StringBuilder(40); |
169 |
StringBuilder sb = new StringBuilder(40); |
Lines 173-189
Link Here
|
173 |
sb.append(isAutocommit()); |
177 |
sb.append(isAutocommit()); |
174 |
log.debug(sb.toString()); |
178 |
log.debug(sb.toString()); |
175 |
} |
179 |
} |
176 |
DefaultConfiguration poolController = new DefaultConfiguration("pool-controller"); // $NON-NLS-1$ |
180 |
poolProperties.setJmxEnabled(true); |
177 |
poolController.setAttribute("max", maxPool); // $NON-NLS-1$ |
181 |
int poolSize = Integer.parseInt(maxPool); |
178 |
poolController.setAttribute("max-strict", "true"); // $NON-NLS-1$ $NON-NLS-2$ |
182 |
poolProperties.setMinIdle(0); |
179 |
poolController.setAttribute("blocking", "true"); // $NON-NLS-1$ $NON-NLS-2$ |
183 |
poolProperties.setInitialSize(poolSize); |
180 |
poolController.setAttribute("timeout", getTimeout()); // $NON-NLS-1$ |
184 |
poolProperties.setMaxIdle(poolSize); |
181 |
poolController.setAttribute("trim-interval", getTrimInterval()); // $NON-NLS-1$ |
185 |
poolProperties.setMaxActive(poolSize); |
182 |
config.addChild(poolController); |
186 |
poolProperties.setMaxWait(Integer.parseInt(getTimeout())); |
183 |
|
187 |
|
184 |
DefaultConfiguration autoCommit = new DefaultConfiguration("auto-commit"); // $NON-NLS-1$ |
188 |
poolProperties.setDefaultAutoCommit(Boolean.valueOf(isAutocommit())); |
185 |
autoCommit.setValue(String.valueOf(isAutocommit())); |
|
|
186 |
config.addChild(autoCommit); |
187 |
|
189 |
|
188 |
if (log.isDebugEnabled()) { |
190 |
if (log.isDebugEnabled()) { |
189 |
StringBuilder sb = new StringBuilder(40); |
191 |
StringBuilder sb = new StringBuilder(40); |
Lines 195-205
Link Here
|
195 |
sb.append(getCheckQuery()); |
197 |
sb.append(getCheckQuery()); |
196 |
log.debug(sb.toString()); |
198 |
log.debug(sb.toString()); |
197 |
} |
199 |
} |
198 |
DefaultConfiguration cfgKeepAlive = new DefaultConfiguration("keep-alive"); // $NON-NLS-1$ |
200 |
poolProperties.setTestOnBorrow(false); |
199 |
cfgKeepAlive.setAttribute("disable", String.valueOf(!isKeepAlive())); // $NON-NLS-1$ |
201 |
poolProperties.setTestOnReturn(false); |
200 |
cfgKeepAlive.setAttribute("age", getConnectionAge()); // $NON-NLS-1$ |
202 |
poolProperties.setTestOnConnect(false); |
201 |
cfgKeepAlive.setValue(getCheckQuery()); |
203 |
|
202 |
poolController.addChild(cfgKeepAlive); |
204 |
if(isKeepAlive()) { |
|
|
205 |
poolProperties.setTestWhileIdle(true); |
206 |
poolProperties.setValidationQuery(getCheckQuery()); |
207 |
// Not sure it is equivalent |
208 |
poolProperties.setMaxAge(Integer.parseInt(getConnectionAge())); |
209 |
poolProperties.setTimeBetweenEvictionRunsMillis(Integer.parseInt(getTrimInterval())); |
210 |
} |
211 |
|
212 |
int transactionIsolation = DataSourceElementBeanInfo.getTransactionIsolationMode(getTransactionIsolation()); |
213 |
if (transactionIsolation >= 0) { |
214 |
poolProperties.setDefaultTransactionIsolation(transactionIsolation); |
215 |
} |
203 |
|
216 |
|
204 |
String _username = getUsername(); |
217 |
String _username = getUsername(); |
205 |
if (log.isDebugEnabled()) { |
218 |
if (log.isDebugEnabled()) { |
Lines 212-249
Link Here
|
212 |
sb.append(_username); |
225 |
sb.append(_username); |
213 |
log.debug(sb.toString()); |
226 |
log.debug(sb.toString()); |
214 |
} |
227 |
} |
215 |
DefaultConfiguration cfgDriver = new DefaultConfiguration("driver"); // $NON-NLS-1$ |
228 |
poolProperties.setDriverClassName(getDriver()); |
216 |
cfgDriver.setValue(getDriver()); |
229 |
poolProperties.setUrl(getDbUrl()); |
217 |
config.addChild(cfgDriver); |
|
|
218 |
DefaultConfiguration cfgDbUrl = new DefaultConfiguration("dburl"); // $NON-NLS-1$ |
219 |
cfgDbUrl.setValue(getDbUrl()); |
220 |
config.addChild(cfgDbUrl); |
221 |
|
230 |
|
222 |
if (_username.length() > 0){ |
231 |
if (_username.length() > 0){ |
223 |
DefaultConfiguration cfgUsername = new DefaultConfiguration("user"); // $NON-NLS-1$ |
232 |
poolProperties.setUsername(_username); |
224 |
cfgUsername.setValue(_username); |
233 |
poolProperties.setPassword(getPassword()); |
225 |
config.addChild(cfgUsername); |
|
|
226 |
DefaultConfiguration cfgPassword = new DefaultConfiguration("password"); // $NON-NLS-1$ |
227 |
cfgPassword.setValue(getPassword()); |
228 |
config.addChild(cfgPassword); |
229 |
} |
234 |
} |
230 |
|
235 |
|
231 |
// log is required to ensure errors are available |
236 |
// log is required to ensure errors are available |
232 |
source.enableLogging(new LogKitLogger(log)); |
237 |
//source.enableLogging(new LogKitLogger(log)); |
233 |
try { |
238 |
DataSource dataSource = new DataSource(); |
234 |
source.configure(config); |
239 |
if(log.isDebugEnabled()) { |
235 |
source.setInstrumentableName(getDataSource()); |
240 |
log.debug("PoolConfiguration:"+poolProperties); |
236 |
} catch (ConfigurationException e) { |
|
|
237 |
log.error("Could not configure datasource for pool: "+getDataSource(),e); |
238 |
} |
241 |
} |
239 |
return source; |
242 |
dataSource.setPoolProperties(poolProperties); |
|
|
243 |
return dataSource; |
240 |
} |
244 |
} |
241 |
|
245 |
|
242 |
// used to hold per-thread singleton connection pools |
246 |
// used to hold per-thread singleton connection pools |
243 |
private static final ThreadLocal<Map<String, ResourceLimitingJdbcDataSource>> perThreadPoolMap = |
247 |
private static final ThreadLocal<Map<String, DataSource>> perThreadPoolMap = |
244 |
new ThreadLocal<Map<String, ResourceLimitingJdbcDataSource>>(){ |
248 |
new ThreadLocal<Map<String, DataSource>>(){ |
245 |
@Override |
249 |
@Override |
246 |
protected Map<String, ResourceLimitingJdbcDataSource> initialValue() { |
250 |
protected Map<String, DataSource> initialValue() { |
247 |
return new HashMap<>(); |
251 |
return new HashMap<>(); |
248 |
} |
252 |
} |
249 |
}; |
253 |
}; |
Lines 253-283
Link Here
|
253 |
* and per-thread pools. |
257 |
* and per-thread pools. |
254 |
* |
258 |
* |
255 |
*/ |
259 |
*/ |
256 |
private class DataSourceComponentImpl implements DataSourceComponent{ |
260 |
private class DataSourceComponentImpl extends DataSourceProxy { |
257 |
|
261 |
|
258 |
private final ResourceLimitingJdbcDataSource sharedDSC; |
262 |
private final DataSource sharedDSC; |
259 |
|
263 |
|
260 |
DataSourceComponentImpl(){ |
264 |
DataSourceComponentImpl(){ |
261 |
sharedDSC=null; |
265 |
sharedDSC=null; |
262 |
} |
266 |
} |
263 |
|
267 |
|
264 |
DataSourceComponentImpl(ResourceLimitingJdbcDataSource p_dsc){ |
268 |
DataSourceComponentImpl(DataSource p_dsc){ |
265 |
sharedDSC=p_dsc; |
269 |
sharedDSC=p_dsc; |
266 |
} |
270 |
} |
267 |
|
271 |
|
268 |
@Override |
272 |
@Override |
269 |
public Connection getConnection() throws SQLException { |
273 |
public Connection getConnection() throws SQLException { |
270 |
Connection conn = null; |
274 |
Connection conn = null; |
271 |
ResourceLimitingJdbcDataSource dsc = null; |
275 |
DataSource dsc = null; |
272 |
if (sharedDSC != null){ // i.e. shared pool |
276 |
if (sharedDSC != null){ // i.e. shared pool |
273 |
dsc = sharedDSC; |
277 |
dsc = sharedDSC; |
274 |
} else { |
278 |
} else { |
275 |
Map<String, ResourceLimitingJdbcDataSource> poolMap = perThreadPoolMap.get(); |
279 |
Map<String, DataSource> poolMap = perThreadPoolMap.get(); |
276 |
dsc = poolMap.get(getDataSource()); |
280 |
dsc = poolMap.get(getDataSourceName()); |
277 |
if (dsc == null){ |
281 |
if (dsc == null){ |
278 |
dsc = initPool("1"); |
282 |
dsc = initPool("1"); |
279 |
poolMap.put(getDataSource(),dsc); |
283 |
poolMap.put(getDataSourceName(),dsc); |
280 |
log.debug("Storing pool: "+dsc.getInstrumentableName()+" @"+System.identityHashCode(dsc)); |
284 |
log.debug("Storing pool: "+dsc.getName()+" @"+System.identityHashCode(dsc)); |
281 |
perThreadPoolSet.add(dsc); |
285 |
perThreadPoolSet.add(dsc); |
282 |
} |
286 |
} |
283 |
} |
287 |
} |
Lines 298-308
Link Here
|
298 |
} |
302 |
} |
299 |
return conn; |
303 |
return conn; |
300 |
} |
304 |
} |
301 |
|
|
|
302 |
@Override |
303 |
public void configure(Configuration arg0) throws ConfigurationException { |
304 |
} |
305 |
|
306 |
} |
305 |
} |
307 |
|
306 |
|
308 |
@Override |
307 |
@Override |
Lines 358-363
Link Here
|
358 |
public void setDataSource(String dataSource) { |
357 |
public void setDataSource(String dataSource) { |
359 |
this.dataSource = dataSource; |
358 |
this.dataSource = dataSource; |
360 |
} |
359 |
} |
|
|
360 |
|
361 |
private String getDataSourceName() { |
362 |
return getDataSource(); |
363 |
} |
361 |
|
364 |
|
362 |
/** |
365 |
/** |
363 |
* @return Returns the dbUrl. |
366 |
* @return Returns the dbUrl. |