parallelized DB connection testing v_0
authorFrantišek Kučera <franta-hg@frantovo.cz>
Sat, 06 Dec 2014 14:38:41 +0100
branchv_0
changeset 1831bb5abfb0655
parent 182 4ff7a273f3e8
child 184 53fb05ce504c
parallelized DB connection testing
java/sql-dk/src/info/globalcode/sql/dk/InfoLister.java
     1.1 --- a/java/sql-dk/src/info/globalcode/sql/dk/InfoLister.java	Sat Dec 06 14:12:59 2014 +0100
     1.2 +++ b/java/sql-dk/src/info/globalcode/sql/dk/InfoLister.java	Sat Dec 06 14:38:41 2014 +0100
     1.3 @@ -43,6 +43,9 @@
     1.4  import java.util.List;
     1.5  import java.util.ServiceLoader;
     1.6  import java.util.Set;
     1.7 +import java.util.concurrent.ExecutorService;
     1.8 +import java.util.concurrent.Executors;
     1.9 +import java.util.concurrent.TimeUnit;
    1.10  import java.util.logging.Level;
    1.11  import java.util.logging.Logger;
    1.12  import javax.sql.rowset.RowSetMetaDataImpl;
    1.13 @@ -59,9 +62,9 @@
    1.14  	 * Fake database name for output formatting
    1.15  	 */
    1.16  	public static final String CONFIG_DB_NAME = "sqldk_configuration";
    1.17 -	private PrintStream out;
    1.18 -	private ConfigurationProvider configurationProvider;
    1.19 -	private CLIOptions options;
    1.20 +	private final PrintStream out;
    1.21 +	private final ConfigurationProvider configurationProvider;
    1.22 +	private final CLIOptions options;
    1.23  	private Formatter formatter;
    1.24  
    1.25  	public InfoLister(PrintStream out, ConfigurationProvider configurationProvider, CLIOptions options) {
    1.26 @@ -131,7 +134,7 @@
    1.27  			data.add(new Object[]{fd.getName(), false, defaultFormatter.equals(fd.getName()), fd.getClassName(), isInstantiable(fd)});
    1.28  		}
    1.29  
    1.30 -		printTable(formatter, header, data, "-- configured and built-in output formatters", null);
    1.31 +		printTable(formatter, header, "-- configured and built-in output formatters", null, data);
    1.32  	}
    1.33  
    1.34  	private boolean isInstantiable(FormatterDefinition fd) {
    1.35 @@ -152,7 +155,7 @@
    1.36  		for (SQLType sqlType : SQLType.values()) {
    1.37  			data.add(new Object[]{sqlType.name(), sqlType.getCode()});
    1.38  		}
    1.39 -		printTable(formatter, header, data, "-- data types", null);
    1.40 +		printTable(formatter, header, "-- data types", null, data);
    1.41  		log.log(Level.INFO, "Type names in --types option are case insensitive");
    1.42  	}
    1.43  
    1.44 @@ -172,7 +175,7 @@
    1.45  			}
    1.46  		}
    1.47  
    1.48 -		printTable(formatter, header, data, "-- configured databases", null);
    1.49 +		printTable(formatter, header, "-- configured databases", null, data);
    1.50  	}
    1.51  
    1.52  	public void listJdbcDrivers() throws FormatterException, ConfigurationException {
    1.53 @@ -195,7 +198,7 @@
    1.54  			});
    1.55  		}
    1.56  
    1.57 -		printTable(formatter, header, data, "-- discovered JDBC drivers (available on the CLASSPATH)", null);
    1.58 +		printTable(formatter, header, "-- discovered JDBC drivers (available on the CLASSPATH)", null, data);
    1.59  	}
    1.60  
    1.61  	public void listJdbcProperties() throws FormatterException, ConfigurationException {
    1.62 @@ -257,7 +260,7 @@
    1.63  				parameters.add(new NamedParameter("driver_major_version", driver.getMajorVersion(), SQLType.INTEGER));
    1.64  				parameters.add(new NamedParameter("driver_minor_version", driver.getMinorVersion(), SQLType.INTEGER));
    1.65  
    1.66 -				printTable(formatter, header, data, "-- configured and configurable JDBC driver properties", parameters);
    1.67 +				printTable(formatter, header, "-- configured and configurable JDBC driver properties", parameters, data);
    1.68  			}
    1.69  		}
    1.70  
    1.71 @@ -277,18 +280,59 @@
    1.72  		return null;
    1.73  	}
    1.74  
    1.75 -	public void testConnection() throws FormatterException, ConfigurationException {
    1.76 +	/**
    1.77 +	 * Parallelism for connection testing – maximum concurrent database connections.
    1.78 +	 */
    1.79 +	private static final int TESTING_THREAD_COUNT = 64;
    1.80 +	/**
    1.81 +	 * Time limit for all connection testing threads – particular timeouts per connection will be
    1.82 +	 * much smaller.
    1.83 +	 */
    1.84 +	private static final long TESTING_AWAIT_LIMIT = 1;
    1.85 +	private static final TimeUnit TESTING_AWAIT_UNIT = TimeUnit.DAYS;
    1.86 +
    1.87 +	public void testConnections() throws FormatterException, ConfigurationException {
    1.88  		ColumnsHeader header = constructHeader(
    1.89  				new HeaderField("database_name", SQLType.VARCHAR),
    1.90  				new HeaderField("configured", SQLType.BOOLEAN),
    1.91  				new HeaderField("connected", SQLType.BOOLEAN));
    1.92 -		List<Object[]> data = new ArrayList<>();
    1.93  
    1.94 -		for (String dbName : options.getDatabaseNamesToTest()) {
    1.95 -			data.add(testConnection(dbName));
    1.96 +		log.log(Level.FINE, "Testing DB connections in {0} threads", TESTING_THREAD_COUNT);
    1.97 +
    1.98 +		ExecutorService es = Executors.newFixedThreadPool(TESTING_THREAD_COUNT);
    1.99 +
   1.100 +		final Formatter currentFormatter = formatter;
   1.101 +
   1.102 +		printHeader(currentFormatter, header, "-- database configuration and connectivity test", null);
   1.103 +
   1.104 +		for (final String dbName : options.getDatabaseNamesToTest()) {
   1.105 +			es.submit(new Runnable() {
   1.106 +				// TODO: Java 8 – lambda
   1.107 +				@Override
   1.108 +				public void run() {
   1.109 +					final Object[] row = testConnection(dbName);
   1.110 +					synchronized (currentFormatter) {
   1.111 +						printRow(currentFormatter, row);
   1.112 +					}
   1.113 +				}
   1.114 +			});
   1.115  		}
   1.116  
   1.117 -		printTable(formatter, header, data, "-- database configuration and connectivity test", null);
   1.118 +		es.shutdown();
   1.119 +
   1.120 +		try {
   1.121 +			log.log(Level.FINEST, "Waiting for test results: {0} {1}", new Object[]{TESTING_AWAIT_LIMIT, TESTING_AWAIT_UNIT.name()});
   1.122 +			boolean finished = es.awaitTermination(TESTING_AWAIT_LIMIT, TESTING_AWAIT_UNIT);
   1.123 +			if (finished) {
   1.124 +				log.log(Level.FINEST, "All testing threads finished in time limit.");
   1.125 +			} else {
   1.126 +				throw new FormatterException("Exceeded total time limit for test threads – this should never happen");
   1.127 +			}
   1.128 +		} catch (InterruptedException e) {
   1.129 +			throw new FormatterException("Interrupted while waiting for test results", e);
   1.130 +		}
   1.131 +
   1.132 +		printFooter(currentFormatter);
   1.133  	}
   1.134  
   1.135  	public Object[] testConnection(String dbName) {
   1.136 @@ -306,7 +350,7 @@
   1.137  			}
   1.138  			log.log(Level.FINE, "Database connection test was successful");
   1.139  		} catch (ConfigurationException | SQLException e) {
   1.140 -			log.log(Level.SEVERE, "Error during testing connection", e);
   1.141 +			log.log(Level.SEVERE, "Error during testing connection " + dbName, e);
   1.142  		}
   1.143  
   1.144  		return new Object[]{dbName, succesfullyConfigured, succesfullyConnected};
   1.145 @@ -331,26 +375,36 @@
   1.146  		out.println(line);
   1.147  	}
   1.148  
   1.149 -	private void printTable(Formatter formatter, ColumnsHeader header, List<Object[]> data, String sql, List<Parameter> parameters) throws ConfigurationException, FormatterException {
   1.150 +	private void printTable(Formatter formatter, ColumnsHeader header, String sql, List<Parameter> parameters, List<Object[]> data) throws ConfigurationException, FormatterException {
   1.151 +		printHeader(formatter, header, sql, parameters);
   1.152 +
   1.153 +		for (Object[] row : data) {
   1.154 +			printRow(formatter, row);
   1.155 +		}
   1.156 +
   1.157 +		printFooter(formatter);
   1.158 +	}
   1.159 +
   1.160 +	private void printHeader(Formatter formatter, ColumnsHeader header, String sql, List<Parameter> parameters) {
   1.161  		formatter.writeStartStatement();
   1.162 -
   1.163  		if (sql != null) {
   1.164  			formatter.writeQuery(sql);
   1.165  			if (parameters != null) {
   1.166  				formatter.writeParameters(parameters);
   1.167  			}
   1.168  		}
   1.169 +		formatter.writeStartResultSet(header);
   1.170 +	}
   1.171  
   1.172 -		formatter.writeStartResultSet(header);
   1.173 +	private void printRow(Formatter formatter, Object[] row) {
   1.174 +		formatter.writeStartRow();
   1.175 +		for (Object cell : row) {
   1.176 +			formatter.writeColumnValue(cell);
   1.177 +		}
   1.178 +		formatter.writeEndRow();
   1.179 +	}
   1.180  
   1.181 -		for (Object[] row : data) {
   1.182 -			formatter.writeStartRow();
   1.183 -			for (Object cell : row) {
   1.184 -				formatter.writeColumnValue(cell);
   1.185 -			}
   1.186 -			formatter.writeEndRow();
   1.187 -		}
   1.188 -
   1.189 +	private void printFooter(Formatter formatter) {
   1.190  		formatter.writeEndResultSet();
   1.191  		formatter.writeEndStatement();
   1.192  	}
   1.193 @@ -397,59 +451,59 @@
   1.194  	public enum InfoType {
   1.195  
   1.196  		HELP {
   1.197 -			@Override
   1.198 -			public void showInfo(InfoLister infoLister) {
   1.199 -				infoLister.printResource(Constants.HELP_FILE);
   1.200 -			}
   1.201 -		},
   1.202 +					@Override
   1.203 +					public void showInfo(InfoLister infoLister) {
   1.204 +						infoLister.printResource(Constants.HELP_FILE);
   1.205 +					}
   1.206 +				},
   1.207  		VERSION {
   1.208 -			@Override
   1.209 -			public void showInfo(InfoLister infoLister) {
   1.210 -				infoLister.printResource(Constants.VERSION_FILE);
   1.211 -			}
   1.212 -		},
   1.213 +					@Override
   1.214 +					public void showInfo(InfoLister infoLister) {
   1.215 +						infoLister.printResource(Constants.VERSION_FILE);
   1.216 +					}
   1.217 +				},
   1.218  		LICENSE {
   1.219 -			@Override
   1.220 -			public void showInfo(InfoLister infoLister) {
   1.221 -				infoLister.printResource(Constants.LICENSE_FILE);
   1.222 -			}
   1.223 -		},
   1.224 +					@Override
   1.225 +					public void showInfo(InfoLister infoLister) {
   1.226 +						infoLister.printResource(Constants.LICENSE_FILE);
   1.227 +					}
   1.228 +				},
   1.229  		FORMATTERS {
   1.230 -			@Override
   1.231 -			public void showInfo(InfoLister infoLister) throws FormatterException, ConfigurationException {
   1.232 -				infoLister.listFormatters();
   1.233 -			}
   1.234 -		},
   1.235 +					@Override
   1.236 +					public void showInfo(InfoLister infoLister) throws FormatterException, ConfigurationException {
   1.237 +						infoLister.listFormatters();
   1.238 +					}
   1.239 +				},
   1.240  		TYPES {
   1.241 -			@Override
   1.242 -			public void showInfo(InfoLister infoLister) throws FormatterException, ConfigurationException {
   1.243 -				infoLister.listTypes();
   1.244 -			}
   1.245 -		},
   1.246 +					@Override
   1.247 +					public void showInfo(InfoLister infoLister) throws FormatterException, ConfigurationException {
   1.248 +						infoLister.listTypes();
   1.249 +					}
   1.250 +				},
   1.251  		JDBC_DRIVERS {
   1.252 -			@Override
   1.253 -			public void showInfo(InfoLister infoLister) throws ConfigurationException, FormatterException {
   1.254 -				infoLister.listJdbcDrivers();
   1.255 -			}
   1.256 -		},
   1.257 +					@Override
   1.258 +					public void showInfo(InfoLister infoLister) throws ConfigurationException, FormatterException {
   1.259 +						infoLister.listJdbcDrivers();
   1.260 +					}
   1.261 +				},
   1.262  		JDBC_PROPERTIES {
   1.263 -			@Override
   1.264 -			public void showInfo(InfoLister infoLister) throws ConfigurationException, FormatterException {
   1.265 -				infoLister.listJdbcProperties();
   1.266 -			}
   1.267 -		},
   1.268 +					@Override
   1.269 +					public void showInfo(InfoLister infoLister) throws ConfigurationException, FormatterException {
   1.270 +						infoLister.listJdbcProperties();
   1.271 +					}
   1.272 +				},
   1.273  		DATABASES {
   1.274 -			@Override
   1.275 -			public void showInfo(InfoLister infoLister) throws FormatterException, ConfigurationException {
   1.276 -				infoLister.listDatabases();
   1.277 -			}
   1.278 -		},
   1.279 +					@Override
   1.280 +					public void showInfo(InfoLister infoLister) throws FormatterException, ConfigurationException {
   1.281 +						infoLister.listDatabases();
   1.282 +					}
   1.283 +				},
   1.284  		CONNECTION {
   1.285 -			@Override
   1.286 -			public void showInfo(InfoLister infoLister) throws FormatterException, ConfigurationException {
   1.287 -				infoLister.testConnection();
   1.288 -			}
   1.289 -		};
   1.290 +					@Override
   1.291 +					public void showInfo(InfoLister infoLister) throws FormatterException, ConfigurationException {
   1.292 +						infoLister.testConnections();
   1.293 +					}
   1.294 +				};
   1.295  
   1.296  		public abstract void showInfo(InfoLister infoLister) throws ConfigurationException, FormatterException;
   1.297  	}