001: // jTDS JDBC Driver for Microsoft SQL Server and Sybase
002: // Copyright (C) 2005 The jTDS Project
003: //
004: // This library is free software; you can redistribute it and/or
005: // modify it under the terms of the GNU Lesser General Public
006: // License as published by the Free Software Foundation; either
007: // version 2.1 of the License, or (at your option) any later version.
008: //
009: // This library is distributed in the hope that it will be useful,
010: // but WITHOUT ANY WARRANTY; without even the implied warranty of
011: // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012: // Lesser General Public License for more details.
013: //
014: // You should have received a copy of the GNU Lesser General Public
015: // License along with this library; if not, write to the Free Software
016: // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
017: //
018: package net.sourceforge.jtds.tools;
019:
020: import junit.framework.TestCase;
021: import java.sql.DriverManager;
022: import java.sql.SQLException;
023: import java.util.Properties;
024: import java.io.PrintWriter;
025:
026: /**
027: * JUnit test class to expose the "All pipe instances are busy" error.
028: * <p>
029: * Run this class from two or more different computers (Linux and/or Windows)
030: * so that multiple requests for the named pipe are hitting the server at the
031: * same time. There are many factors that exacerbate the issue, although
032: * using SQL Server 6.5, slow (higher latency) TCP/IP connections and adding
033: * more computers hitting the server simultaneously seem to be the top three.
034: * <p>
035: * See also <a href="http://support.microsoft.com/default.aspx?scid=KB;EN-US;165189">
036: * INF: Multiple Named Pipes Connections May Cause Error 17832</a> on
037: * Microsoft's knowledgebase web site.
038: *
039: * @author David D. Kilzer
040: * @version $Id: TestAllPipeInstancesAreBusy.java,v 1.2 2005/09/06 22:57:08 ddkilzer Exp $
041: */
042: public class TestAllPipeInstancesAreBusy extends TestCase {
043:
044: private static final Properties CONNECTION_PROPERTIES = new Properties();
045: private static final String CONNECTION_URL = "jdbc:jtds:sqlserver://HOSTNAME/DATABASENAME;namedPipe=true;TDS=4.2";
046:
047: public static void main(String[] args) {
048: new TestAllPipeInstancesAreBusy("main")
049: .testAllPipeInstancesAreBusy();
050: }
051:
052: static {
053: //DriverManager.setLogWriter(new PrintWriter(System.err));
054: try {
055: // Register the driver
056: Class.forName("net.sourceforge.jtds.jdbc.Driver");
057: } catch (ClassNotFoundException e) {
058: throw new RuntimeException(e);
059: }
060: }
061:
062: public TestAllPipeInstancesAreBusy(String name) {
063: super (name);
064: }
065:
066: /**
067: * Test method that creates <code>concurrentCount</code> threads, then calls
068: * {@link #connectToDatabaseAndClose()} to connect to the database. This keeps
069: * the computer running this method very busy trying to establish connections
070: * to the database. One computer is not enough to cause the "All pipe
071: * instances are busy" error, though.
072: */
073: public void testAllPipeInstancesAreBusy() {
074:
075: final int concurrentCount = 100;
076:
077: final ConnectionRunnable[] cr = new ConnectionRunnable[concurrentCount];
078: final Thread[] t = new Thread[concurrentCount];
079:
080: for (int i = 0; i < concurrentCount; i++) {
081: cr[i] = new ConnectionRunnable("r" + String.valueOf(i));
082: t[i] = new Thread(cr[i]);
083: }
084:
085: for (int i = 0; i < concurrentCount; i++) {
086: t[i].start();
087: }
088:
089: try {
090: for (int i = 0; i < concurrentCount; i++) {
091: t[i].join();
092: }
093: } catch (InterruptedException e) {
094: e.printStackTrace(System.err);
095: throw new RuntimeException(e);
096: }
097:
098: boolean result = true;
099: for (int i = 0; i < concurrentCount; i++) {
100: result = result && cr[i].isPassed();
101: }
102: if (!result) {
103: throw new AssertionError();
104: }
105: }
106:
107: /**
108: * Connects to the database, does (optional) work, then disconnects.
109: *
110: * @throws SQLException on error.
111: */
112: private void connectToDatabaseAndClose() throws SQLException {
113: DriverManager.getConnection(CONNECTION_URL,
114: CONNECTION_PROPERTIES).close();
115: }
116:
117: /**
118: * Class instantiated for each thread that calls
119: * {@link TestAllPipeInstancesAreBusy#connectToDatabaseAndClose()}
120: * continuously.
121: */
122: private class ConnectionRunnable implements Runnable {
123:
124: private boolean passed;
125: private String name;
126: private int count;
127:
128: public ConnectionRunnable(String name) {
129: this .name = name;
130: }
131:
132: public void run() {
133: try {
134: passed = true;
135: count = 0;
136: while (true) {
137: connectToDatabaseAndClose();
138: count++;
139: }
140: } catch (Exception e) {
141: System.err.print(name + ": " + count + ": ");
142: e.printStackTrace(System.err);
143: passed = false;
144: }
145: }
146:
147: public boolean isPassed() {
148: return passed;
149: }
150: }
151:
152: }
|