001: /*
002: * This software is released under a licence similar to the Apache Software Licence.
003: * See org.logicalcobwebs.proxool.package.html for details.
004: * The latest version is available at http://proxool.sourceforge.net
005: */
006: package org.logicalcobwebs.proxool;
007:
008: import org.apache.commons.logging.Log;
009: import org.apache.commons.logging.LogFactory;
010: import org.logicalcobwebs.proxool.admin.StatisticsIF;
011: import org.logicalcobwebs.proxool.admin.StatisticsListenerIF;
012: import org.logicalcobwebs.proxool.admin.SnapshotIF;
013:
014: import java.sql.Connection;
015: import java.sql.DriverManager;
016: import java.sql.SQLException;
017: import java.sql.Statement;
018: import java.util.Properties;
019: import java.text.DecimalFormat;
020:
021: /**
022: * Tests how fast Proxool is compared to the "perfect" pool, {@link SimpoolAdapter}.
023: *
024: * @version $Revision: 1.18 $, $Date: 2006/01/18 14:40:06 $
025: * @author Bill Horsman (bill@logicalcobwebs.co.uk)
026: * @author $Author: billhorsman $ (current maintainer)
027: * @since Proxool 0.5
028: */
029: public class PerformanceTest extends AbstractProxoolTest implements
030: StatisticsListenerIF {
031:
032: private static final Log LOG = LogFactory
033: .getLog(PerformanceTest.class);
034:
035: private static DecimalFormat millisecondsFormat = new DecimalFormat(
036: "0.00");
037:
038: private Thread waitingThead;
039:
040: private StatisticsIF statistics;
041: private static final int PERIOD = 5;
042: private static final int COUNT = 6;
043: private long servedCount;
044:
045: public PerformanceTest(String s) {
046: super (s);
047: }
048:
049: /**
050: * Test how many connections we can serve if we go as fast as we can!
051: * @throws ProxoolException if anything goes wrong
052: */
053: public void testPerformance() throws ProxoolException,
054: InterruptedException {
055:
056: waitingThead = Thread.currentThread();
057:
058: String alias = "testPeformance";
059: int threadCount = 20;
060: String url = TestHelper.buildProxoolUrl(alias,
061: TestConstants.HYPERSONIC_DRIVER,
062: TestConstants.HYPERSONIC_TEST_URL);
063: Properties info = new Properties();
064: info.setProperty(ProxoolConstants.USER_PROPERTY,
065: TestConstants.HYPERSONIC_USER);
066: info.setProperty(ProxoolConstants.PASSWORD_PROPERTY,
067: TestConstants.HYPERSONIC_PASSWORD);
068: info.setProperty(
069: ProxoolConstants.MINIMUM_CONNECTION_COUNT_PROPERTY,
070: String.valueOf(threadCount));
071: info.setProperty(ProxoolConstants.VERBOSE_PROPERTY, String
072: .valueOf(Boolean.TRUE));
073: info.setProperty(
074: ProxoolConstants.MAXIMUM_CONNECTION_COUNT_PROPERTY,
075: String.valueOf(threadCount));
076: /*
077: info.setProperty(ProxoolConstants.STATISTICS_PROPERTY, String.valueOf(PERIOD) + "s");
078: info.setProperty(ProxoolConstants.STATISTICS_LOG_LEVEL_PROPERTY, ProxoolConstants.STATISTICS_LOG_LEVEL_INFO);
079: */
080: ProxoolFacade.registerConnectionPool(url, info);
081: /*
082: ProxoolFacade.addStatisticsListener(alias, this);
083: */
084:
085: doWait();
086:
087: AnnoyingConnector[] annoyingConnectors = new AnnoyingConnector[threadCount];
088: for (int i = 0; i < annoyingConnectors.length; i++) {
089: annoyingConnectors[i] = new AnnoyingConnector(alias);
090: Thread t = new Thread(annoyingConnectors[i]);
091: t.start();
092: }
093:
094: for (int i = 0; i < COUNT; i++) {
095: doWait();
096: }
097:
098: for (int i = 0; i < annoyingConnectors.length; i++) {
099: annoyingConnectors[i].cancel();
100: }
101:
102: for (int i = 0; i < 5; i++) {
103: int activeConnectionCount = ProxoolFacade
104: .getSnapshot(alias).getActiveConnectionCount();
105: if (activeConnectionCount > 0) {
106: LOG
107: .info("Waiting for 10 seconds for connections to become inactive ("
108: + activeConnectionCount + ")");
109: Thread.sleep(10000);
110: } else {
111: break;
112: }
113: }
114:
115: final SnapshotIF snapshot = ProxoolFacade.getSnapshot(alias,
116: true);
117: LOG
118: .info("Active count: "
119: + snapshot.getActiveConnectionCount());
120: LOG.info("Available count: "
121: + snapshot.getAvailableConnectionCount());
122: ConnectionInfoIF[] cis = snapshot.getConnectionInfos();
123: LOG.info("Found " + cis.length
124: + " connetions with a detailed snapshot" + "");
125: for (int i = 0; i < cis.length; i++) {
126: ConnectionInfoIF ci = cis[i];
127: LOG.info("#"
128: + ci.getId()
129: + ": "
130: + ci.getStatus()
131: + ", lap="
132: + (ci.getTimeLastStopActive() - ci
133: .getTimeLastStartActive()));
134: }
135: LOG.info("Served a total of "
136: + ProxoolFacade.getSnapshot(alias).getServedCount());
137:
138: }
139:
140: private void doWait() {
141: synchronized (Thread.currentThread()) {
142: try {
143: Thread.currentThread().wait(60000);
144: } catch (InterruptedException e) {
145: fail("Statistics didn't arrive as expected");
146: }
147: }
148: }
149:
150: public void statistics(String alias, StatisticsIF statistics) {
151: this .servedCount += statistics.getServedCount();
152: this .statistics = statistics;
153: synchronized (waitingThead) {
154: waitingThead.notify();
155: }
156: }
157:
158: public void testSnapshotImpact() throws ProxoolException {
159:
160: waitingThead = Thread.currentThread();
161:
162: String alias = "testPeformance";
163: int threadCount = 10;
164: String url = TestHelper.buildProxoolUrl(alias,
165: TestConstants.HYPERSONIC_DRIVER,
166: TestConstants.HYPERSONIC_TEST_URL);
167: Properties info = new Properties();
168: info.setProperty(ProxoolConstants.USER_PROPERTY,
169: TestConstants.HYPERSONIC_USER);
170: info.setProperty(ProxoolConstants.PASSWORD_PROPERTY,
171: TestConstants.HYPERSONIC_PASSWORD);
172: info.setProperty(
173: ProxoolConstants.MINIMUM_CONNECTION_COUNT_PROPERTY,
174: String.valueOf(threadCount));
175: info.setProperty(
176: ProxoolConstants.MAXIMUM_CONNECTION_COUNT_PROPERTY,
177: String.valueOf(threadCount));
178: info.setProperty(ProxoolConstants.STATISTICS_PROPERTY, String
179: .valueOf(PERIOD)
180: + "s");
181: info.setProperty(
182: ProxoolConstants.STATISTICS_LOG_LEVEL_PROPERTY,
183: ProxoolConstants.STATISTICS_LOG_LEVEL_INFO);
184: info.setProperty(ProxoolConstants.VERBOSE_PROPERTY, String
185: .valueOf(Boolean.TRUE));
186: ProxoolFacade.registerConnectionPool(url, info);
187: ProxoolFacade.addStatisticsListener(alias, this );
188: DisagreeableSnapshotter disagreeableSnapshotter = new DisagreeableSnapshotter(
189: alias);
190: new Thread(disagreeableSnapshotter).start();
191:
192: AnnoyingConnector[] annoyingConnectors = new AnnoyingConnector[threadCount];
193: for (int i = 0; i < annoyingConnectors.length; i++) {
194: annoyingConnectors[i] = new AnnoyingConnector(alias);
195: Thread t = new Thread(annoyingConnectors[i]);
196: t.start();
197: }
198:
199: doWait();
200:
201: int servedCount = 0;
202: for (int i = 0; i < COUNT; i++) {
203: doWait();
204: servedCount += statistics.getServedCount();
205: assertTrue("disparityNoticed", !disagreeableSnapshotter
206: .isDisparityNoticed());
207: }
208:
209: for (int i = 0; i < annoyingConnectors.length; i++) {
210: annoyingConnectors[i].cancel();
211: }
212: disagreeableSnapshotter.cancel();
213:
214: long start = System.currentTimeMillis();
215: while (System.currentTimeMillis() - start < 30000) {
216: int threadsRunning = 0;
217: for (int i = 0; i < annoyingConnectors.length; i++) {
218: if (annoyingConnectors[i].isRunning()) {
219: threadsRunning++;
220: }
221: }
222: if (disagreeableSnapshotter.isRunning()) {
223: threadsRunning++;
224: }
225: if (threadsRunning == 0) {
226: break;
227: }
228: }
229:
230: assertTrue("disparityNoticed", !disagreeableSnapshotter
231: .isDisparityNoticed());
232:
233: LOG.info("Served "
234: + servedCount
235: + " at "
236: + millisecondsFormat
237: .format((double) (1000 * PERIOD * COUNT)
238: / (double) servedCount)
239: + " ms per connection");
240:
241: }
242:
243: class DisagreeableSnapshotter implements Runnable {
244:
245: private String alias;
246:
247: private boolean cancelled;
248:
249: private boolean disparityNoticed;
250:
251: private boolean running;
252:
253: public DisagreeableSnapshotter(String alias) {
254: this .alias = alias;
255: }
256:
257: public void run() {
258:
259: running = true;
260: int snapshotCount = 0;
261: while (!cancelled) {
262: try {
263: Thread.sleep(100);
264: } catch (InterruptedException e) {
265: LOG.error("Awoken", e);
266: }
267: try {
268: SnapshotIF s = ProxoolFacade.getSnapshot(alias,
269: true);
270: int c1 = s.getActiveConnectionCount();
271: int c2 = getCount(s.getConnectionInfos(),
272: ConnectionInfoIF.STATUS_ACTIVE);
273: int v1 = s.getAvailableConnectionCount();
274: int v2 = getCount(s.getConnectionInfos(),
275: ConnectionInfoIF.STATUS_AVAILABLE);
276: int o1 = s.getOfflineConnectionCount();
277: int o2 = getCount(s.getConnectionInfos(),
278: ConnectionInfoIF.STATUS_OFFLINE);
279: if (c1 != c2 || v1 != v2 || o1 != o2) {
280: LOG.error("Disparity noticed. Active: " + c1
281: + (c1 == c2 ? " == " : " != ") + c2
282: + ", available: " + v1
283: + (v1 == v2 ? " == " : " != ") + v2
284: + ", offline: " + o1
285: + (o1 == o2 ? " == " : " != ") + o2);
286: disparityNoticed = true;
287: }
288: snapshotCount++;
289: } catch (ProxoolException e) {
290: LOG.error("Couldn't get snapshot", e);
291: }
292: }
293: LOG.info(snapshotCount + " snapshots taken");
294: running = false;
295: }
296:
297: public boolean isRunning() {
298: return running;
299: }
300:
301: private int getCount(ConnectionInfoIF[] connectionInfos,
302: int status) {
303: int count = 0;
304: for (int i = 0; i < connectionInfos.length; i++) {
305: if (connectionInfos[i].getStatus() == status) {
306: count++;
307: }
308: }
309: return count;
310: }
311:
312: public boolean isDisparityNoticed() {
313: return disparityNoticed;
314: }
315:
316: public void cancel() {
317: cancelled = true;
318: }
319:
320: }
321:
322: class AnnoyingConnector implements Runnable {
323:
324: private String alias;
325:
326: private boolean cancelled;
327:
328: private int exceptionCount;
329:
330: private boolean running = false;
331:
332: public AnnoyingConnector(String alias) {
333: this .alias = alias;
334: }
335:
336: public void run() {
337: running = true;
338: while (!cancelled) {
339: try {
340: Connection connection = null;
341: Statement s = null;
342: try {
343: connection = DriverManager
344: .getConnection(TestHelper
345: .buildProxoolUrl(alias));
346: s = connection.createStatement();
347: Thread.yield();
348: } finally {
349: if (s != null) {
350: s.close();
351: }
352: if (connection != null) {
353: connection.close();
354: }
355: }
356: } catch (SQLException e) {
357: LOG.error(Thread.currentThread().getName(), e);
358: exceptionCount++;
359: }
360: }
361: running = false;
362: }
363:
364: public boolean isRunning() {
365: return running;
366: }
367:
368: public void cancel() {
369: cancelled = true;
370: }
371:
372: public int getExceptionCount() {
373: return exceptionCount;
374: }
375:
376: }
377:
378: }
379:
380: /*
381: Revision history:
382: $Log: PerformanceTest.java,v $
383: Revision 1.18 2006/01/18 14:40:06 billhorsman
384: Unbundled Jakarta's Commons Logging.
385:
386: Revision 1.17 2003/11/04 13:54:02 billhorsman
387: checkstyle
388:
389: Revision 1.16 2003/03/11 14:58:32 billhorsman
390: put PerformanceTest back in the global test
391:
392: Revision 1.15 2003/03/11 14:51:43 billhorsman
393: more concurrency fixes relating to snapshots
394:
395: Revision 1.14 2003/03/10 23:49:04 billhorsman
396: new test to measure the impact of taking snapshots
397:
398: Revision 1.13 2003/03/10 15:31:26 billhorsman
399: fixes
400:
401: Revision 1.12 2003/03/04 10:24:40 billhorsman
402: removed try blocks around each test
403:
404: Revision 1.11 2003/03/03 17:08:57 billhorsman
405: all tests now extend AbstractProxoolTest
406:
407: Revision 1.10 2003/03/03 11:12:04 billhorsman
408: fixed licence
409:
410: Revision 1.9 2003/03/01 15:27:24 billhorsman
411: checkstyle
412:
413: Revision 1.8 2003/02/19 15:14:23 billhorsman
414: fixed copyright (copy and paste error,
415: not copyright change)
416:
417: Revision 1.7 2003/02/06 17:41:03 billhorsman
418: now uses imported logging
419:
420: Revision 1.6 2002/12/16 17:05:05 billhorsman
421: new test structure
422:
423: Revision 1.5 2002/11/09 16:01:53 billhorsman
424: fix doc
425:
426: Revision 1.4 2002/11/02 14:22:16 billhorsman
427: Documentation
428:
429: Revision 1.3 2002/11/02 13:57:34 billhorsman
430: checkstyle
431:
432: Revision 1.2 2002/11/02 11:37:48 billhorsman
433: New tests
434:
435: Revision 1.1 2002/10/30 21:17:51 billhorsman
436: new performance tests
437:
438: */
|