loadbalancingconnectionproxy.java
来自「mysql5.0 JDBC 驱动 放在glassfish或者tomcat的li」· Java 代码 · 共 535 行 · 第 1/2 页
JAVA
535 行
* Closes current connection and removes it from required mappings.
*
* @throws SQLException
*/
synchronized void invalidateCurrentConnection() throws SQLException {
try {
if (!this.currentConn.isClosed()) {
this.currentConn.close();
}
} finally {
// add host to the global blacklist, if enabled
if (this.isGlobalBlacklistEnabled()) {
this.addToGlobalBlacklist((String) this.connectionsToHostsMap.get(this.currentConn));
}
// remove from liveConnections
this.liveConnections.remove(this.connectionsToHostsMap
.get(this.currentConn));
int hostIndex = ((Integer) this.hostsToListIndexMap
.get(this.connectionsToHostsMap.get(this.currentConn)))
.intValue();
// reset the statistics for the host
synchronized (this.responseTimes) {
this.responseTimes[hostIndex] = 0;
}
this.connectionsToHostsMap.remove(this.currentConn);
}
}
/**
* Proxies method invocation on the java.sql.Connection interface, trapping
* "close", "isClosed" and "commit/rollback" (to switch connections for load
* balancing).
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
String methodName = method.getName();
if ("equals".equals(methodName) && args.length == 1) {
if (args[0] instanceof Proxy) {
return Boolean.valueOf((((Proxy)args[0]).equals(this)));
}
return Boolean.valueOf(equals(args[0]));
}
if ("close".equals(methodName)) {
synchronized (this.liveConnections) {
// close all underlying connections
Iterator allConnections = this.liveConnections.values()
.iterator();
while (allConnections.hasNext()) {
((Connection) allConnections.next()).close();
}
if (!this.isClosed) {
this.balancer.destroy();
}
this.liveConnections.clear();
this.connectionsToHostsMap.clear();
}
return null;
}
if ("isClosed".equals(methodName)) {
return Boolean.valueOf(this.isClosed);
}
if (this.isClosed) {
throw SQLError.createSQLException(
"No operations allowed after connection closed.",
SQLError.SQL_STATE_CONNECTION_NOT_OPEN);
}
if (!inTransaction) {
this.inTransaction = true;
this.transactionStartTime = getLocalTimeBestResolution();
}
Object result = null;
try {
result = method.invoke(this.currentConn, args);
if (result != null) {
if (result instanceof com.mysql.jdbc.Statement) {
((com.mysql.jdbc.Statement)result).setPingTarget(this);
}
result = proxyIfInterfaceIsJdbc(result, result.getClass());
}
} catch (InvocationTargetException e) {
dealWithInvocationException(e);
} finally {
if ("commit".equals(methodName) || "rollback".equals(methodName)) {
this.inTransaction = false;
// Update stats
String host = (String) this.connectionsToHostsMap.get(this.currentConn);
// avoid NPE if the connection has already been removed from connectionsToHostsMap
// in invalidateCurrenctConnection()
if ( host != null ) {
int hostIndex = ((Integer) this.hostsToListIndexMap
.get( host ))
.intValue();
synchronized (this.responseTimes) {
this.responseTimes[hostIndex] = getLocalTimeBestResolution()
- this.transactionStartTime;
}
}
pickNewConnection();
}
}
return result;
}
/**
* Picks the "best" connection to use for the next transaction based on the
* BalanceStrategy in use.
*
* @throws SQLException
*/
private synchronized void pickNewConnection() throws SQLException {
if (this.currentConn == null) {
this.currentConn = this.balancer.pickConnection(this,
Collections.unmodifiableList(this.hostList),
Collections.unmodifiableMap(this.liveConnections),
(long[]) this.responseTimes.clone(),
this.retriesAllDown);
return;
}
Connection newConn = this.balancer.pickConnection(this,
Collections.unmodifiableList(this.hostList),
Collections.unmodifiableMap(this.liveConnections),
(long[]) this.responseTimes.clone(),
this.retriesAllDown);
newConn.setTransactionIsolation(this.currentConn
.getTransactionIsolation());
newConn.setAutoCommit(this.currentConn.getAutoCommit());
this.currentConn = newConn;
}
/**
* Recursively checks for interfaces on the given object to determine if it
* implements a java.sql interface, and if so, proxies the instance so that
* we can catch and fire SQL errors.
*
* @param toProxy
* @param clazz
* @return
*/
Object proxyIfInterfaceIsJdbc(Object toProxy, Class clazz) {
Class[] interfaces = clazz.getInterfaces();
for (int i = 0; i < interfaces.length; i++) {
String packageName = interfaces[i].getPackage().getName();
if ("java.sql".equals(packageName)
|| "javax.sql".equals(packageName)) {
return Proxy.newProxyInstance(toProxy.getClass()
.getClassLoader(), interfaces,
new ConnectionErrorFiringInvocationHandler(toProxy));
}
return proxyIfInterfaceIsJdbc(toProxy, interfaces[i]);
}
return toProxy;
}
/**
* Returns best-resolution representation of local time, using nanoTime() if
* availble, otherwise defaulting to currentTimeMillis().
*/
private static long getLocalTimeBestResolution() {
if (getLocalTimeMethod != null) {
try {
return ((Long) getLocalTimeMethod.invoke(null, null))
.longValue();
} catch (IllegalArgumentException e) {
// ignore - we fall through to currentTimeMillis()
} catch (IllegalAccessException e) {
// ignore - we fall through to currentTimeMillis()
} catch (InvocationTargetException e) {
// ignore - we fall through to currentTimeMillis()
}
}
return System.currentTimeMillis();
}
public synchronized void doPing() throws SQLException {
Iterator allConns = this.liveConnections.values().iterator();
while (allConns.hasNext()) {
((Connection)allConns.next()).ping();
}
}
public void addToGlobalBlacklist(String host) {
if(this.isGlobalBlacklistEnabled()) {
synchronized(globalBlacklist){
globalBlacklist.put(host, new Long(System.currentTimeMillis()
+ this.globalBlacklistTimeout));
}
}
}
public boolean isGlobalBlacklistEnabled() {
return (this.globalBlacklistTimeout > 0);
}
public Map getGlobalBlacklist() {
if(!this.isGlobalBlacklistEnabled()) {
return new HashMap(1);
}
// Make a local copy of the blacklist
Map blacklistClone = new HashMap(globalBlacklist.size());
// Copy everything from synchronized global blacklist to local copy for manipulation
synchronized (globalBlacklist) {
blacklistClone.putAll(globalBlacklist);
}
Set keys = blacklistClone.keySet();
// we're only interested in blacklisted hosts that are in the hostList
keys.retainAll(this.hostList);
if(keys.size() == this.hostList.size()){
// return an empty blacklist, let the BalanceStrategy implementations try to connect to everything
// since it appears that all hosts are unavailable - we don't want to wait for
// loadBalanceBlacklistTimeout to expire.
return new HashMap(1);
}
// Don't need to synchronize here as we using a local copy
for(Iterator i = keys.iterator(); i.hasNext(); ) {
String host = (String) i.next();
// OK if null is returned because another thread already purged Map entry.
Long timeout = (Long) globalBlacklist.get(host);
if(timeout != null && timeout.longValue() < System.currentTimeMillis()){
// Timeout has expired, remove from blacklist
synchronized(globalBlacklist){
globalBlacklist.remove(host);
}
blacklistClone.remove(host);
}
}
return blacklistClone;
}
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?