00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
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.SQLException;
00031 import java.sql.Statement;
00032 import java.util.ArrayList;
00033
00034 import javax.management.NotCompliantMBeanException;
00035
00036 import org.objectweb.cjdbc.common.exceptions.BadConnectionException;
00037 import org.objectweb.cjdbc.common.exceptions.UnreachableBackendException;
00038 import org.objectweb.cjdbc.common.i18n.Translate;
00039 import org.objectweb.cjdbc.common.jmx.mbeans.AbstractLoadBalancerMBean;
00040 import org.objectweb.cjdbc.common.log.Trace;
00041 import org.objectweb.cjdbc.common.sql.AbstractRequest;
00042 import org.objectweb.cjdbc.common.sql.AbstractWriteRequest;
00043 import org.objectweb.cjdbc.common.sql.SelectRequest;
00044 import org.objectweb.cjdbc.common.sql.StoredProcedure;
00045 import org.objectweb.cjdbc.common.sql.filters.MacrosHandler;
00046 import org.objectweb.cjdbc.common.xml.DatabasesXmlTags;
00047 import org.objectweb.cjdbc.common.xml.XmlComponent;
00048 import org.objectweb.cjdbc.controller.backend.DatabaseBackend;
00049 import org.objectweb.cjdbc.controller.backend.DriverCompliance;
00050 import org.objectweb.cjdbc.controller.cache.metadata.MetadataCache;
00051 import org.objectweb.cjdbc.controller.connection.AbstractConnectionManager;
00052 import org.objectweb.cjdbc.controller.jmx.AbstractStandardMBean;
00053 import org.objectweb.cjdbc.controller.requestmanager.TransactionMarkerMetaData;
00054 import org.objectweb.cjdbc.controller.virtualdatabase.ControllerResultSet;
00055 import org.objectweb.cjdbc.controller.virtualdatabase.VirtualDatabase;
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069 public abstract class AbstractLoadBalancer extends AbstractStandardMBean
00070 implements
00071 XmlComponent,
00072 AbstractLoadBalancerMBean
00073 {
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087 protected VirtualDatabase vdb;
00088 protected int raidbLevel;
00089 protected int parsingGranularity;
00090
00091 protected static Trace logger = Trace
00092 .getLogger("org.objectweb.cjdbc.controller.loadbalancer");
00093
00094 protected MacrosHandler macroHandler;
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105 protected AbstractLoadBalancer(VirtualDatabase vdb, int raidbLevel,
00106 int parsingGranularity) throws SQLException, NotCompliantMBeanException
00107 {
00108 super(AbstractLoadBalancerMBean.class);
00109 this.raidbLevel = raidbLevel;
00110 this.parsingGranularity = parsingGranularity;
00111 this.vdb = vdb;
00112 try
00113 {
00114 vdb.acquireReadLockBackendLists();
00115 }
00116 catch (InterruptedException e)
00117 {
00118 String msg = Translate.get(
00119 "loadbalancer.backendlist.acquire.readlock.failed", e);
00120 logger.error(msg);
00121 throw new SQLException(msg);
00122 }
00123 int size = vdb.getBackends().size();
00124 ArrayList backends = vdb.getBackends();
00125 for (int i = 0; i < size; i++)
00126 {
00127 DatabaseBackend backend = (DatabaseBackend) backends.get(i);
00128 if (backend.isReadEnabled() || backend.isWriteEnabled())
00129 {
00130 if (logger.isWarnEnabled())
00131 logger.warn(Translate.get(
00132 "loadbalancer.constructor.backends.not.disabled", backend
00133 .getName()));
00134 try
00135 {
00136 disableBackend(backend);
00137 }
00138 catch (Exception e)
00139 {
00140 backend.disable();
00141 }
00142 }
00143 }
00144 vdb.releaseReadLockBackendLists();
00145 }
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156 public int getRAIDbLevel()
00157 {
00158 return raidbLevel;
00159 }
00160
00161
00162
00163
00164
00165
00166 public void setRAIDbLevel(int raidbLevel)
00167 {
00168 this.raidbLevel = raidbLevel;
00169 }
00170
00171
00172
00173
00174
00175
00176 public int getParsingGranularity()
00177 {
00178 return parsingGranularity;
00179 }
00180
00181
00182
00183
00184
00185
00186 public void setParsingGranularity(int parsingGranularity)
00187 {
00188 this.parsingGranularity = parsingGranularity;
00189 }
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204 public abstract ControllerResultSet execReadRequest(SelectRequest request,
00205 MetadataCache metadataCache) throws SQLException;
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217 public abstract int execWriteRequest(AbstractWriteRequest request)
00218 throws AllBackendsFailedException, SQLException;
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231 public abstract ControllerResultSet execWriteRequestWithKeys(
00232 AbstractWriteRequest request, MetadataCache metadataCache)
00233 throws AllBackendsFailedException, SQLException;
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244 public abstract ControllerResultSet execReadOnlyReadStoredProcedure(
00245 StoredProcedure proc, MetadataCache metadataCache) throws SQLException;
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256 public abstract ControllerResultSet execReadStoredProcedure(
00257 StoredProcedure proc, MetadataCache metadataCache) throws SQLException;
00258
00259
00260
00261
00262
00263
00264
00265
00266 public abstract int execWriteStoredProcedure(StoredProcedure proc)
00267 throws SQLException;
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282 public static final ControllerResultSet executeSelectRequestOnBackend(
00283 SelectRequest request, DatabaseBackend backend, Connection c,
00284 MetadataCache metadataCache) throws SQLException, BadConnectionException
00285 {
00286 ControllerResultSet rs = null;
00287 try
00288 {
00289 backend.addPendingReadRequest(request);
00290 String sql = request.getSQL();
00291
00292 sql = backend.rewriteQuery(sql);
00293
00294 Statement s;
00295 if (request.isDriverProcessed() || (request.getSqlSkeleton() == null))
00296 s = c.createStatement();
00297 else
00298 {
00299 s = c.prepareStatement(request.getSqlSkeleton());
00300 org.objectweb.cjdbc.driver.PreparedStatement.setPreparedStatement(sql,
00301 (PreparedStatement) s);
00302 }
00303
00304
00305 DriverCompliance driverCompliance = backend.getDriverCompliance();
00306 if (driverCompliance.supportSetQueryTimeout())
00307 s.setQueryTimeout(request.getTimeout());
00308 if ((request.getCursorName() != null)
00309 && (driverCompliance.supportSetCursorName()))
00310 s.setCursorName(request.getCursorName());
00311 if ((request.getFetchSize() != 0)
00312 && driverCompliance.supportSetFetchSize())
00313 s.setFetchSize(request.getFetchSize());
00314 if ((request.getMaxRows() > 0) && driverCompliance.supportSetMaxRows())
00315 s.setMaxRows(request.getMaxRows());
00316 if (request.isDriverProcessed() || (request.getSqlSkeleton() == null))
00317 rs = new ControllerResultSet(request, s.executeQuery(sql),
00318 metadataCache, s);
00319 else
00320 rs = new ControllerResultSet(request, ((PreparedStatement) s)
00321 .executeQuery(), metadataCache, s);
00322 }
00323 catch (SQLException e)
00324 {
00325 if (backend.isValidConnection(c))
00326 throw e;
00327 else
00328 throw new BadConnectionException(e);
00329 }
00330 finally
00331 {
00332 backend.removePendingRequest(request);
00333 }
00334 return rs;
00335 }
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349 public static final int executeUpdateRequestOnBackend(
00350 AbstractWriteRequest request, DatabaseBackend backend, Connection c)
00351 throws SQLException, BadConnectionException
00352 {
00353 try
00354 {
00355 backend.addPendingWriteRequest(request);
00356 String sql = request.getSQL();
00357
00358 sql = backend.rewriteQuery(sql);
00359
00360 Statement s;
00361 if (request.isDriverProcessed() || (request.getSqlSkeleton() == null))
00362 s = c.createStatement();
00363 else
00364 {
00365 s = c.prepareStatement(request.getSqlSkeleton());
00366 org.objectweb.cjdbc.driver.PreparedStatement.setPreparedStatement(sql,
00367 (PreparedStatement) s);
00368 }
00369
00370
00371 DriverCompliance driverCompliance = backend.getDriverCompliance();
00372 if (driverCompliance.supportSetQueryTimeout())
00373 s.setQueryTimeout(request.getTimeout());
00374
00375 int rows = 0;
00376 if (request.isDriverProcessed() || (request.getSqlSkeleton() == null))
00377 rows = s.executeUpdate(sql);
00378 else
00379 rows = ((PreparedStatement) s).executeUpdate();
00380
00381 s.close();
00382 return rows;
00383 }
00384 catch (SQLException e)
00385 {
00386 if (backend.isValidConnection(c))
00387 throw e;
00388 else
00389 throw new BadConnectionException(e);
00390 }
00391 finally
00392 {
00393 backend.removePendingRequest(request);
00394 }
00395 }
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410 public static final ControllerResultSet executeUpdateRequestOnBackendWithKeys(
00411 AbstractWriteRequest request, DatabaseBackend backend, Connection c,
00412 MetadataCache metadataCache) throws SQLException, BadConnectionException
00413 {
00414 try
00415 {
00416 backend.addPendingWriteRequest(request);
00417 String sql = request.getSQL();
00418
00419 sql = backend.rewriteQuery(sql);
00420
00421 Statement s = c.createStatement();
00422
00423
00424 DriverCompliance driverCompliance = backend.getDriverCompliance();
00425 if (driverCompliance.supportSetQueryTimeout())
00426 s.setQueryTimeout(request.getTimeout());
00427
00428 s.executeUpdate(sql, Statement.RETURN_GENERATED_KEYS);
00429 ControllerResultSet rs = new ControllerResultSet(request, s
00430 .getGeneratedKeys(), metadataCache, s);
00431 return rs;
00432 }
00433 catch (SQLException e)
00434 {
00435 if (backend.isValidConnection(c))
00436 throw e;
00437 else
00438 throw new BadConnectionException(e);
00439 }
00440 finally
00441 {
00442 backend.removePendingRequest(request);
00443 }
00444 }
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458 public static final ControllerResultSet executeReadStoredProcedureOnBackend(
00459 StoredProcedure proc, DatabaseBackend backend, Connection c,
00460 MetadataCache metadataCache) throws SQLException, BadConnectionException
00461 {
00462 try
00463 {
00464 backend.addPendingReadRequest(proc);
00465
00466
00467
00468 CallableStatement cs;
00469 if (proc.isDriverProcessed())
00470 cs = c.prepareCall(proc.getSQL());
00471 else
00472 {
00473 cs = c.prepareCall(proc.getSqlSkeleton());
00474 org.objectweb.cjdbc.driver.PreparedStatement.setPreparedStatement(proc
00475 .getSQL(), cs);
00476 }
00477 if (backend.getDriverCompliance().supportSetQueryTimeout())
00478 cs.setQueryTimeout(proc.getTimeout());
00479 if ((proc.getMaxRows() > 0)
00480 && backend.getDriverCompliance().supportSetMaxRows())
00481 cs.setMaxRows(proc.getMaxRows());
00482 ControllerResultSet rs = new ControllerResultSet(proc, cs.executeQuery(),
00483 metadataCache, cs);
00484 return rs;
00485 }
00486 catch (SQLException e)
00487 {
00488 if (backend.isValidConnection(c))
00489 throw e;
00490 else
00491 throw new BadConnectionException(e);
00492 }
00493 finally
00494 {
00495 backend.removePendingRequest(proc);
00496 }
00497 }
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510 public static final int executeWriteStoredProcedureOnBackend(
00511 StoredProcedure proc, DatabaseBackend backend, Connection c)
00512 throws SQLException, BadConnectionException
00513 {
00514 try
00515 {
00516 backend.addPendingWriteRequest(proc);
00517
00518
00519
00520 CallableStatement cs;
00521 if (proc.isDriverProcessed())
00522 cs = c.prepareCall(proc.getSQL());
00523 else
00524 {
00525 cs = c.prepareCall(proc.getSqlSkeleton());
00526 org.objectweb.cjdbc.driver.PreparedStatement.setPreparedStatement(proc
00527 .getSQL(), cs);
00528 }
00529 if (backend.getDriverCompliance().supportSetQueryTimeout())
00530 cs.setQueryTimeout(proc.getTimeout());
00531 if ((proc.getMaxRows() > 0)
00532 && backend.getDriverCompliance().supportSetMaxRows())
00533 cs.setMaxRows(proc.getMaxRows());
00534 int rows = cs.executeUpdate();
00535 cs.close();
00536 return rows;
00537 }
00538 catch (SQLException e)
00539 {
00540 if (backend.isValidConnection(c))
00541 throw e;
00542 else
00543 throw new BadConnectionException(e);
00544 }
00545 finally
00546 {
00547 backend.removePendingRequest(proc);
00548 }
00549 }
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561 public abstract void begin(TransactionMarkerMetaData tm) throws SQLException;
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571 public abstract void commit(TransactionMarkerMetaData tm)
00572 throws AllBackendsFailedException, SQLException;
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582 public abstract void rollback(TransactionMarkerMetaData tm)
00583 throws AllBackendsFailedException, SQLException;
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598 public abstract void enableBackend(DatabaseBackend db, boolean writeEnabled)
00599 throws SQLException;
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610 public abstract void disableBackend(DatabaseBackend db) throws SQLException;
00611
00612
00613
00614
00615
00616
00617
00618
00619 public void setWeight(String name, int w) throws SQLException
00620 {
00621 throw new SQLException("Weight is not supported by this load balancer");
00622 }
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633 public abstract String getInformation();
00634
00635
00636
00637
00638
00639
00640 public abstract String getXmlImpl();
00641
00642
00643
00644
00645
00646
00647
00648
00649 public void setMacroHandler(MacrosHandler handler)
00650 {
00651 this.macroHandler = handler;
00652 }
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662 public void handleMacros(AbstractRequest request)
00663 {
00664 if (macroHandler == null)
00665 return;
00666
00667 if (request.isWriteRequest())
00668 {
00669 AbstractWriteRequest writeReq = (AbstractWriteRequest) request;
00670 if (writeReq.isCreate() || writeReq.isAlter() || writeReq.isDrop())
00671 return;
00672 }
00673
00674 if (request.isDriverProcessed() || (request.getSqlSkeleton() == null))
00675 request.setSQL(macroHandler.processMacros(request.getSQL()));
00676 else
00677 request.setSqlSkeleton(macroHandler.processMacros(request
00678 .getSqlSkeleton()));
00679 }
00680
00681
00682
00683
00684 public String getXml()
00685 {
00686 StringBuffer info = new StringBuffer();
00687 info.append("<" + DatabasesXmlTags.ELT_LoadBalancer + ">");
00688 info.append(getXmlImpl());
00689 info.append("</" + DatabasesXmlTags.ELT_LoadBalancer + ">");
00690 return info.toString();
00691 }
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707 public static final Connection getConnectionAndBeginTransaction(
00708 DatabaseBackend backend, AbstractConnectionManager cm, long tid)
00709 throws SQLException, UnreachableBackendException
00710 {
00711 Connection c = null;
00712 boolean isConnectionValid = false;
00713 do
00714 {
00715 c = cm.getConnection(tid);
00716
00717
00718 if (c == null)
00719 throw new UnreachableBackendException(Translate.get(
00720 "loadbalancer.unable.get.connection", new String[]{
00721 String.valueOf(tid), backend.getName()}));
00722 try
00723 {
00724 c.setAutoCommit(false);
00725 isConnectionValid = true;
00726 }
00727 catch (SQLException e)
00728 {
00729 if (backend.isValidConnection(c))
00730 throw e;
00731 else
00732 {
00733 cm.deleteConnection(tid);
00734 }
00735 }
00736 }
00737 while (!isConnectionValid);
00738 return c;
00739 }
00740
00741
00742
00743
00744 public String getAssociatedString()
00745 {
00746 return "loadbalancer";
00747 }
00748 }