00001
00025 package org.objectweb.cjdbc.controller.loadbalancer;
00026
00027
import java.sql.CallableStatement;
00028
import java.sql.Connection;
00029
import java.sql.PreparedStatement;
00030
import java.sql.ResultSet;
00031
import java.sql.SQLException;
00032
import java.sql.Statement;
00033
import java.util.ArrayList;
00034
00035
import org.objectweb.cjdbc.common.exceptions.BadConnectionException;
00036
import org.objectweb.cjdbc.common.i18n.Translate;
00037
import org.objectweb.cjdbc.common.log.Trace;
00038
import org.objectweb.cjdbc.common.sql.AbstractRequest;
00039
import org.objectweb.cjdbc.common.sql.AbstractWriteRequest;
00040
import org.objectweb.cjdbc.common.sql.SelectRequest;
00041
import org.objectweb.cjdbc.common.sql.StoredProcedure;
00042
import org.objectweb.cjdbc.common.sql.filters.MacrosHandler;
00043
import org.objectweb.cjdbc.common.xml.DatabasesXmlTags;
00044
import org.objectweb.cjdbc.common.xml.XmlComponent;
00045
import org.objectweb.cjdbc.controller.backend.DatabaseBackend;
00046
import org.objectweb.cjdbc.controller.backend.DriverCompliance;
00047
import org.objectweb.cjdbc.controller.cache.metadata.MetadataCache;
00048
import org.objectweb.cjdbc.controller.requestmanager.TransactionMarkerMetaData;
00049
import org.objectweb.cjdbc.controller.virtualdatabase.ControllerResultSet;
00050
import org.objectweb.cjdbc.controller.virtualdatabase.VirtualDatabase;
00051
00064 public abstract class AbstractLoadBalancer implements XmlComponent
00065 {
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079 protected VirtualDatabase
vdb;
00080 protected int raidbLevel;
00081 protected int parsingGranularity;
00082
00083 protected static Trace
logger = Trace
00084 .getLogger(
"org.objectweb.cjdbc.controller.loadbalancer");
00085
00086 protected MacrosHandler
macroHandler;
00087
00097 protected AbstractLoadBalancer(VirtualDatabase vdb,
int raidbLevel,
00098
int parsingGranularity)
throws SQLException
00099 {
00100
this.raidbLevel =
raidbLevel;
00101
this.parsingGranularity =
parsingGranularity;
00102
this.vdb =
vdb;
00103
try
00104 {
00105
vdb.acquireReadLockBackendLists();
00106 }
00107
catch (InterruptedException e)
00108 {
00109 String msg =
Translate.get(
00110
"loadbalancer.backendlist.acquire.readlock.failed", e);
00111
logger.error(msg);
00112
throw new SQLException(msg);
00113 }
00114
int size =
vdb.getBackends().size();
00115 ArrayList backends =
vdb.getBackends();
00116
for (
int i = 0; i < size; i++)
00117 {
00118
DatabaseBackend backend = (
DatabaseBackend) backends.get(i);
00119
if (backend.
isReadEnabled() || backend.
isWriteEnabled())
00120 {
00121
if (
logger.isWarnEnabled())
00122
logger.warn(
Translate.get(
00123
"loadbalancer.constructor.backends.not.disabled", backend
00124 .
getName()));
00125 backend.
disable();
00126 }
00127 }
00128
vdb.releaseReadLockBackendLists();
00129 }
00130
00131
00132
00133
00134
00140 public int getRAIDbLevel()
00141 {
00142
return raidbLevel;
00143 }
00144
00150 public void setRAIDbLevel(
int raidbLevel)
00151 {
00152
this.raidbLevel = raidbLevel;
00153 }
00154
00160 public int getParsingGranularity()
00161 {
00162
return parsingGranularity;
00163 }
00164
00170 public void setParsingGranularity(
int parsingGranularity)
00171 {
00172
this.parsingGranularity = parsingGranularity;
00173 }
00174
00175
00176
00177
00178
00188
public abstract ControllerResultSet execReadRequest(
SelectRequest request,
00189
MetadataCache metadataCache)
throws SQLException;
00190
00201
public abstract int execWriteRequest(
AbstractWriteRequest request)
00202
throws AllBackendsFailedException, SQLException;
00203
00215
public abstract ControllerResultSet execWriteRequestWithKeys(
00216
AbstractWriteRequest request,
MetadataCache metadataCache)
00217
throws AllBackendsFailedException, SQLException;
00218
00228
public abstract ControllerResultSet execReadOnlyReadStoredProcedure(
00229
StoredProcedure proc,
MetadataCache metadataCache)
throws SQLException;
00230
00240
public abstract ControllerResultSet execReadStoredProcedure(
00241
StoredProcedure proc,
MetadataCache metadataCache)
throws SQLException;
00242
00250
public abstract int execWriteStoredProcedure(
StoredProcedure proc)
00251
throws SQLException;
00252
00266 public static ControllerResultSet executeSelectRequestOnBackend(
00267
SelectRequest request,
DatabaseBackend backend, Connection c,
00268
MetadataCache metadataCache)
throws SQLException,
BadConnectionException
00269 {
00270
ControllerResultSet rs = null;
00271
try
00272 {
00273 backend.addPendingReadRequest(request);
00274 String sql = request.getSQL();
00275
00276 sql = backend.rewriteQuery(sql);
00277
00278
Statement s;
00279
if (request.isDriverProcessed() || (request.getSqlSkeleton() == null))
00280 s = c.createStatement();
00281
else
00282 {
00283 s = c.prepareStatement(request.getSqlSkeleton());
00284 org.objectweb.cjdbc.driver.PreparedStatement.setPreparedStatement(sql,
00285 (PreparedStatement) s);
00286 }
00287
00288
00289
DriverCompliance driverCompliance = backend.getDriverCompliance();
00290
if (driverCompliance.
supportSetQueryTimeout())
00291 s.
setQueryTimeout(request.getTimeout());
00292
if ((request.getCursorName() != null)
00293 && (driverCompliance.
supportSetCursorName()))
00294 s.
setCursorName(request.getCursorName());
00295
if ((request.getFetchSize() != 0)
00296 && driverCompliance.
supportSetFetchSize())
00297 s.
setFetchSize(request.getFetchSize());
00298
if ((request.getMaxRows() > 0) && driverCompliance.
supportSetMaxRows())
00299 s.
setMaxRows(request.getMaxRows());
00300
if (request.isDriverProcessed() || (request.getSqlSkeleton() == null))
00301 rs =
new ControllerResultSet(request, s.
executeQuery(sql),
00302 metadataCache);
00303
else
00304 rs =
new ControllerResultSet(request, ((PreparedStatement) s)
00305 .executeQuery(), metadataCache);
00306 }
00307
catch (SQLException e)
00308 {
00309
if (backend.isValidConnection(c))
00310
throw e;
00311
else
00312
throw new BadConnectionException(e);
00313 }
00314 finally
00315 {
00316 backend.removePendingRequest(request);
00317 }
00318
return rs;
00319 }
00320
00333 public static int executeUpdateRequestOnBackend(
AbstractWriteRequest request,
00334
DatabaseBackend backend, Connection c)
throws SQLException,
00335
BadConnectionException
00336 {
00337
try
00338 {
00339 backend.addPendingWriteRequest(request);
00340 String sql = request.getSQL();
00341
00342 sql = backend.rewriteQuery(sql);
00343
00344
Statement s;
00345
if (request.isDriverProcessed() || (request.getSqlSkeleton() == null))
00346 s = c.createStatement();
00347
else
00348 {
00349 s = c.prepareStatement(request.getSqlSkeleton());
00350 org.objectweb.cjdbc.driver.PreparedStatement.setPreparedStatement(sql,
00351 (PreparedStatement) s);
00352 }
00353
00354
00355
DriverCompliance driverCompliance = backend.getDriverCompliance();
00356
if (driverCompliance.
supportSetQueryTimeout())
00357 s.
setQueryTimeout(request.getTimeout());
00358
00359
if (request.isDriverProcessed() || (request.getSqlSkeleton() == null))
00360
return s.
executeUpdate(sql);
00361
else
00362
return ((PreparedStatement) s).executeUpdate();
00363 }
00364
catch (SQLException e)
00365 {
00366
if (backend.isValidConnection(c))
00367
throw e;
00368
else
00369
throw new BadConnectionException(e);
00370 }
00371 finally
00372 {
00373 backend.removePendingRequest(request);
00374 }
00375 }
00376
00389 public static ResultSet
executeUpdateRequestOnBackendWithKeys(
00390
AbstractWriteRequest request,
DatabaseBackend backend, Connection c)
00391
throws SQLException,
BadConnectionException
00392 {
00393
try
00394 {
00395 backend.addPendingWriteRequest(request);
00396 String sql = request.getSQL();
00397
00398 sql = backend.rewriteQuery(sql);
00399
00400
Statement s = c.createStatement();
00401
00402
00403
DriverCompliance driverCompliance = backend.getDriverCompliance();
00404
if (driverCompliance.
supportSetQueryTimeout())
00405 s.
setQueryTimeout(request.getTimeout());
00406
00407 s.
executeUpdate(sql,
Statement.RETURN_GENERATED_KEYS);
00408
return s.
getGeneratedKeys();
00409 }
00410
catch (SQLException e)
00411 {
00412
if (backend.isValidConnection(c))
00413
throw e;
00414
else
00415
throw new BadConnectionException(e);
00416 }
00417 finally
00418 {
00419 backend.removePendingRequest(request);
00420 }
00421 }
00422
00435 public static ControllerResultSet executeReadStoredProcedureOnBackend(
00436
StoredProcedure proc,
DatabaseBackend backend, Connection c,
00437
MetadataCache metadataCache)
throws SQLException,
BadConnectionException
00438 {
00439
try
00440 {
00441 backend.addPendingReadRequest(proc);
00442
00443
00444
00445 CallableStatement cs;
00446
if (proc.isDriverProcessed())
00447 cs = c.prepareCall(proc.getSQL());
00448
else
00449 {
00450 cs = c.prepareCall(proc.getSqlSkeleton());
00451 org.objectweb.cjdbc.driver.PreparedStatement.setPreparedStatement(proc
00452 .getSQL(), cs);
00453 }
00454
if (backend.getDriverCompliance().supportSetQueryTimeout())
00455 cs.setQueryTimeout(proc.getTimeout());
00456
if ((proc.getMaxRows() > 0)
00457 && backend.getDriverCompliance().supportSetMaxRows())
00458 cs.setMaxRows(proc.getMaxRows());
00459
return new ControllerResultSet(proc, cs.executeQuery(), metadataCache);
00460 }
00461
catch (SQLException e)
00462 {
00463
if (backend.isValidConnection(c))
00464
throw e;
00465
else
00466
throw new BadConnectionException(e);
00467 }
00468 finally
00469 {
00470 backend.removePendingRequest(proc);
00471 }
00472 }
00473
00485 public static int executeWriteStoredProcedureOnBackend(
StoredProcedure proc,
00486
DatabaseBackend backend, Connection c)
throws SQLException,
00487
BadConnectionException
00488 {
00489
try
00490 {
00491 backend.addPendingWriteRequest(proc);
00492
00493
00494
00495 CallableStatement cs;
00496
if (proc.isDriverProcessed())
00497 cs = c.prepareCall(proc.getSQL());
00498
else
00499 {
00500 cs = c.prepareCall(proc.getSqlSkeleton());
00501 org.objectweb.cjdbc.driver.PreparedStatement.setPreparedStatement(proc
00502 .getSQL(), cs);
00503 }
00504
if (backend.getDriverCompliance().supportSetQueryTimeout())
00505 cs.setQueryTimeout(proc.getTimeout());
00506
if ((proc.getMaxRows() > 0)
00507 && backend.getDriverCompliance().supportSetMaxRows())
00508 cs.setMaxRows(proc.getMaxRows());
00509
return cs.executeUpdate();
00510 }
00511
catch (SQLException e)
00512 {
00513
if (backend.isValidConnection(c))
00514
throw e;
00515
else
00516
throw new BadConnectionException(e);
00517 }
00518 finally
00519 {
00520 backend.removePendingRequest(proc);
00521 }
00522 }
00523
00524
00525
00526
00527
00534
public abstract void begin(
TransactionMarkerMetaData tm)
throws SQLException;
00535
00544
public abstract void commit(
TransactionMarkerMetaData tm)
00545
throws AllBackendsFailedException, SQLException;
00546
00555
public abstract void rollback(
TransactionMarkerMetaData tm)
00556
throws AllBackendsFailedException, SQLException;
00557
00558
00559
00560
00561
00571
public abstract void enableBackend(
DatabaseBackend db,
boolean writeEnabled)
00572
throws SQLException;
00573
00583
public abstract void disableBackend(
DatabaseBackend db)
throws SQLException;
00584
00592 public void setWeight(String name,
int w)
throws SQLException
00593 {
00594
throw new SQLException(
"Weight is not supported by this load balancer");
00595 }
00596
00597
00598
00599
00600
00606
public abstract String
getInformation();
00607
00613
public abstract String
getXmlImpl();
00614
00622 public void setMacroHandler(MacrosHandler handler)
00623 {
00624
this.macroHandler = handler;
00625 }
00626
00635 public void handleMacros(
AbstractRequest request)
00636 {
00637
if (
macroHandler == null)
00638
return;
00639
00640
if (request.
isDriverProcessed() || (request.
getSqlSkeleton() == null))
00641 request.
setSQL(
macroHandler.processMacros(request.
getSQL()));
00642
else
00643 request.
setSqlSkeleton(
macroHandler.processMacros(request
00644 .
getSqlSkeleton()));
00645 }
00646
00650 public String
getXml()
00651 {
00652 StringBuffer info =
new StringBuffer();
00653 info.append(
"<" +
DatabasesXmlTags.ELT_LoadBalancer +
">");
00654 info.append(
getXmlImpl());
00655 info.append(
"</" +
DatabasesXmlTags.ELT_LoadBalancer +
">");
00656
return info.toString();
00657 }
00658
00659 }