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.singledb;
00026
00027 import java.sql.Connection;
00028 import java.sql.SQLException;
00029
00030 import org.objectweb.cjdbc.common.exceptions.BadConnectionException;
00031 import org.objectweb.cjdbc.common.exceptions.UnreachableBackendException;
00032 import org.objectweb.cjdbc.common.i18n.Translate;
00033 import org.objectweb.cjdbc.common.log.Trace;
00034 import org.objectweb.cjdbc.common.sql.AbstractWriteRequest;
00035 import org.objectweb.cjdbc.common.sql.ParsingGranularities;
00036 import org.objectweb.cjdbc.common.sql.SelectRequest;
00037 import org.objectweb.cjdbc.common.sql.StoredProcedure;
00038 import org.objectweb.cjdbc.common.xml.DatabasesXmlTags;
00039 import org.objectweb.cjdbc.controller.backend.DatabaseBackend;
00040 import org.objectweb.cjdbc.controller.cache.metadata.MetadataCache;
00041 import org.objectweb.cjdbc.controller.connection.AbstractConnectionManager;
00042 import org.objectweb.cjdbc.controller.loadbalancer.AbstractLoadBalancer;
00043 import org.objectweb.cjdbc.controller.requestmanager.RAIDbLevels;
00044 import org.objectweb.cjdbc.controller.requestmanager.TransactionMarkerMetaData;
00045 import org.objectweb.cjdbc.controller.virtualdatabase.ControllerResultSet;
00046 import org.objectweb.cjdbc.controller.virtualdatabase.VirtualDatabase;
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059 public class SingleDB extends AbstractLoadBalancer
00060 {
00061
00062
00063
00064
00065
00066
00067 private DatabaseBackend backend;
00068
00069 private static Trace logger = Trace
00070 .getLogger("org.objectweb.cjdbc.controller.loadbalancer.SingleDB");
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083 public SingleDB(VirtualDatabase vdb) throws Exception
00084 {
00085
00086 super(vdb, RAIDbLevels.SingleDB, ParsingGranularities.NO_PARSING);
00087 }
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102 public ControllerResultSet execReadRequest(SelectRequest request,
00103 MetadataCache metadataCache) throws SQLException
00104 {
00105 if (backend == null)
00106 throw new SQLException(Translate.get(
00107 "loadbalancer.execute.no.backend.available", request.getId()));
00108
00109 try
00110 {
00111 AbstractConnectionManager cm = backend.getConnectionManager(request
00112 .getLogin());
00113 if (request.isAutoCommit())
00114 {
00115 ControllerResultSet rs = null;
00116 boolean badConnection;
00117 do
00118 {
00119 badConnection = false;
00120
00121 Connection c = null;
00122 try
00123 {
00124 c = cm.getConnection();
00125 }
00126 catch (UnreachableBackendException e1)
00127 {
00128 String backendName = backend.getName();
00129 logger.error(Translate.get(
00130 "loadbalancer.backend.disabling.unreachable", backendName));
00131 disableBackend(backend);
00132 backend = null;
00133 throw new SQLException(Translate.get(
00134 "loadbalancer.backend.unreacheable", backendName));
00135 }
00136
00137
00138 if (c == null)
00139 throw new SQLException(Translate.get(
00140 "loadbalancer.backend.no.connection", backend.getName()));
00141
00142
00143 try
00144 {
00145 rs = executeSelectRequestOnBackend(request, backend, c,
00146 metadataCache);
00147 cm.releaseConnection(c);
00148 }
00149 catch (SQLException e)
00150 {
00151 cm.releaseConnection(c);
00152 throw new SQLException(Translate.get(
00153 "loadbalancer.request.failed.on.backend", new String[]{
00154 request.getSQLShortForm(vdb.getSQLShortFormLength()),
00155 backend.getName(), e.getMessage()}));
00156 }
00157 catch (BadConnectionException e)
00158 {
00159 cm.deleteConnection(c);
00160 badConnection = true;
00161 }
00162 }
00163 while (badConnection);
00164 return rs;
00165 }
00166 else
00167 {
00168 long tid = request.getTransactionId();
00169
00170 Connection c = cm.retrieveConnection(tid);
00171
00172
00173 if (c == null)
00174 throw new SQLException(Translate.get(
00175 "loadbalancer.unable.retrieve.connection", new String[]{
00176 String.valueOf(tid), backend.getName()}));
00177
00178
00179 ControllerResultSet rs = null;
00180 try
00181 {
00182 rs = executeSelectRequestOnBackend(request, backend, c, metadataCache);
00183 }
00184 catch (SQLException e)
00185 {
00186 throw new SQLException(Translate.get(
00187 "loadbalancer.request.failed.on.backend", new String[]{
00188 request.getSQLShortForm(vdb.getSQLShortFormLength()),
00189 backend.getName(), e.getMessage()}));
00190 }
00191 catch (BadConnectionException e)
00192 {
00193 cm.deleteConnection(tid);
00194 throw new SQLException(Translate.get(
00195 "loadbalancer.connection.failed", new String[]{
00196 String.valueOf(tid), backend.getName(), e.getMessage()}));
00197 }
00198 return rs;
00199 }
00200 }
00201 catch (RuntimeException e)
00202 {
00203 String msg = "Request '"
00204 + request.getSQLShortForm(vdb.getSQLShortFormLength())
00205 + "' failed on backend " + backend.getURL() + " (" + e + ")";
00206 logger.fatal(msg, e);
00207 throw new SQLException(msg);
00208 }
00209 }
00210
00211
00212
00213
00214
00215
00216
00217
00218 public int execWriteRequest(AbstractWriteRequest request) throws SQLException
00219 {
00220 if (backend == null)
00221 throw new SQLException(Translate.get(
00222 "loadbalancer.execute.no.backend.available", request.getId()));
00223
00224 try
00225 {
00226 AbstractConnectionManager cm = backend.getConnectionManager(request
00227 .getLogin());
00228 if (request.isAutoCommit())
00229 {
00230
00231
00232 if (backend.isDisabling())
00233 throw new SQLException(Translate.get(
00234 "loadbalancer.backend.is.disabling", new String[]{
00235 request.getSQLShortForm(vdb.getSQLShortFormLength()),
00236 backend.getName()}));
00237
00238
00239 Connection c = null;
00240 try
00241 {
00242 c = cm.getConnection();
00243 }
00244 catch (UnreachableBackendException e1)
00245 {
00246 String backendName = backend.getName();
00247 logger.error(Translate.get(
00248 "loadbalancer.backend.disabling.unreachable", backendName));
00249 disableBackend(backend);
00250 backend = null;
00251 throw new SQLException(Translate.get(
00252 "loadbalancer.backend.unreacheable", backendName));
00253 }
00254
00255
00256 if (c == null)
00257 throw new SQLException(Translate.get(
00258 "loadbalancer.backend.no.connection", backend.getName()));
00259
00260
00261 int result;
00262 try
00263 {
00264 result = executeUpdateRequestOnBackend(request, backend, c);
00265 }
00266 catch (Exception e)
00267 {
00268 throw new SQLException(Translate.get(
00269 "loadbalancer.request.failed.on.backend", new String[]{
00270 request.getSQLShortForm(vdb.getSQLShortFormLength()),
00271 backend.getName(), e.getMessage()}));
00272 }
00273 finally
00274 {
00275 cm.releaseConnection(c);
00276 }
00277 return result;
00278 }
00279 else
00280 {
00281 Connection c = cm.retrieveConnection(request.getTransactionId());
00282
00283
00284 if (c == null)
00285 throw new SQLException(Translate.get(
00286 "loadbalancer.unable.retrieve.connection",
00287 new String[]{String.valueOf(request.getTransactionId()),
00288 backend.getName()}));
00289
00290
00291 try
00292 {
00293 return executeUpdateRequestOnBackend(request, backend, c);
00294 }
00295 catch (Exception e)
00296 {
00297 throw new SQLException(Translate.get(
00298 "loadbalancer.request.failed.on.backend", new String[]{
00299 request.getSQLShortForm(vdb.getSQLShortFormLength()),
00300 backend.getName(), e.getMessage()}));
00301 }
00302 }
00303 }
00304 catch (RuntimeException e)
00305 {
00306 String msg = Translate.get("loadbalancer.request.failed.on.backend",
00307 new String[]{request.getSQLShortForm(vdb.getSQLShortFormLength()),
00308 backend.getName(), e.getMessage()});
00309 logger.fatal(msg, e);
00310 throw new SQLException(msg);
00311 }
00312 }
00313
00314
00315
00316
00317
00318 public ControllerResultSet execWriteRequestWithKeys(
00319 AbstractWriteRequest request, MetadataCache metadataCache)
00320 throws SQLException
00321 {
00322 if (backend == null)
00323 throw new SQLException(Translate.get(
00324 "loadbalancer.execute.no.backend.available", request.getId()));
00325
00326 if (!backend.getDriverCompliance().supportGetGeneratedKeys())
00327 throw new SQLException(Translate.get(
00328 "loadbalancer.backend.autogeneratedkeys.unsupported", backend
00329 .getName()));
00330
00331 try
00332 {
00333 AbstractConnectionManager cm = backend.getConnectionManager(request
00334 .getLogin());
00335 if (request.isAutoCommit())
00336 {
00337
00338
00339 if (backend.isDisabling())
00340 throw new SQLException(Translate.get(
00341 "loadbalancer.backend.is.disabling", new String[]{
00342 request.getSQLShortForm(vdb.getSQLShortFormLength()),
00343 backend.getName()}));
00344
00345
00346 Connection c = null;
00347 try
00348 {
00349 c = cm.getConnection();
00350 }
00351 catch (UnreachableBackendException e1)
00352 {
00353 String backendName = backend.getName();
00354 logger.error(Translate.get(
00355 "loadbalancer.backend.disabling.unreachable", backendName));
00356 disableBackend(backend);
00357 backend = null;
00358 throw new SQLException(Translate.get(
00359 "loadbalancer.backend.unreacheable", backendName));
00360 }
00361
00362
00363 if (c == null)
00364 throw new SQLException(Translate.get(
00365 "loadbalancer.backend.no.connection", backend.getName()));
00366
00367
00368 ControllerResultSet result;
00369 try
00370 {
00371 result = executeUpdateRequestOnBackendWithKeys(request, backend, c,
00372 metadataCache);
00373 }
00374 catch (Exception e)
00375 {
00376 throw new SQLException(Translate.get(
00377 "loadbalancer.request.failed.on.backend", new String[]{
00378 request.getSQLShortForm(vdb.getSQLShortFormLength()),
00379 backend.getName(), e.getMessage()}));
00380 }
00381 finally
00382 {
00383 cm.releaseConnection(c);
00384 }
00385 return result;
00386 }
00387 else
00388 {
00389
00390 Connection c = cm.retrieveConnection(request.getTransactionId());
00391
00392
00393 if (c == null)
00394 throw new SQLException(Translate.get(
00395 "loadbalancer.unable.retrieve.connection",
00396 new String[]{String.valueOf(request.getTransactionId()),
00397 backend.getName()}));
00398
00399
00400 try
00401 {
00402 return executeUpdateRequestOnBackendWithKeys(request, backend, c,
00403 metadataCache);
00404 }
00405 catch (Exception e)
00406 {
00407 throw new SQLException(Translate.get(
00408 "loadbalancer.request.failed.on.backend", new String[]{
00409 request.getSQLShortForm(vdb.getSQLShortFormLength()),
00410 backend.getName(), e.getMessage()}));
00411 }
00412 finally
00413 {
00414 backend.removePendingRequest(request);
00415 }
00416 }
00417 }
00418 catch (RuntimeException e)
00419 {
00420 String msg = Translate.get("loadbalancer.request.failed.on.backend",
00421 new String[]{request.getSQLShortForm(vdb.getSQLShortFormLength()),
00422 backend.getName(), e.getMessage()});
00423 logger.fatal(msg, e);
00424 throw new SQLException(msg);
00425 }
00426 }
00427
00428
00429
00430
00431
00432 public ControllerResultSet execReadOnlyReadStoredProcedure(
00433 StoredProcedure proc, MetadataCache metadataCache) throws SQLException
00434 {
00435 return execReadStoredProcedure(proc, metadataCache);
00436 }
00437
00438
00439
00440
00441
00442 public ControllerResultSet execReadStoredProcedure(StoredProcedure proc,
00443 MetadataCache metadataCache) throws SQLException
00444 {
00445 if (backend == null)
00446 throw new SQLException(
00447 "No available backend to execute stored procedure " + proc.getId());
00448
00449 try
00450 {
00451 AbstractConnectionManager cm = backend.getConnectionManager(proc
00452 .getLogin());
00453 if (proc.isAutoCommit())
00454 {
00455 Connection c = null;
00456 try
00457 {
00458 c = cm.getConnection();
00459 }
00460 catch (UnreachableBackendException e1)
00461 {
00462 String backendName = backend.getName();
00463 logger.error(Translate.get(
00464 "loadbalancer.backend.disabling.unreachable", backendName));
00465 disableBackend(backend);
00466 backend = null;
00467 throw new SQLException(Translate.get(
00468 "loadbalancer.backend.unreacheable", backendName));
00469 }
00470
00471
00472 if (c == null)
00473 throw new SQLException(Translate.get(
00474 "loadbalancer.backend.no.connection", backend.getName()));
00475
00476
00477 ControllerResultSet rs = null;
00478 try
00479 {
00480 rs = AbstractLoadBalancer.executeReadStoredProcedureOnBackend(proc,
00481 backend, c, metadataCache);
00482 }
00483 catch (Exception e)
00484 {
00485 throw new SQLException(Translate.get(
00486 "loadbalancer.storedprocedure.failed.on.backend", new String[]{
00487 proc.getSQLShortForm(vdb.getSQLShortFormLength()),
00488 backend.getName(), e.getMessage()}));
00489 }
00490 finally
00491 {
00492 cm.releaseConnection(c);
00493 }
00494 return rs;
00495 }
00496 else
00497 {
00498 Connection c = cm.retrieveConnection(proc.getTransactionId());
00499
00500
00501 if (c == null)
00502 throw new SQLException(Translate.get(
00503 "loadbalancer.unable.retrieve.connection", new String[]{
00504 String.valueOf(proc.getTransactionId()), backend.getName()}));
00505
00506
00507 try
00508 {
00509 return AbstractLoadBalancer.executeReadStoredProcedureOnBackend(proc,
00510 backend, c, metadataCache);
00511 }
00512 catch (Exception e)
00513 {
00514 throw new SQLException(Translate.get(
00515 "loadbalancer.storedprocedure.failed.on.backend", new String[]{
00516 proc.getSQLShortForm(vdb.getSQLShortFormLength()),
00517 backend.getName(), e.getMessage()}));
00518 }
00519 }
00520 }
00521 catch (RuntimeException e)
00522 {
00523 String msg = Translate.get(
00524 "loadbalancer.storedprocedure.failed.on.backend", new String[]{
00525 proc.getSQLShortForm(vdb.getSQLShortFormLength()),
00526 backend.getName(), e.getMessage()});
00527 logger.fatal(msg, e);
00528 throw new SQLException(msg);
00529 }
00530 }
00531
00532
00533
00534
00535 public int execWriteStoredProcedure(StoredProcedure proc) throws SQLException
00536 {
00537 if (backend == null)
00538 throw new SQLException(
00539 "No available backend to execute stored procedure " + proc.getId());
00540
00541 try
00542 {
00543 AbstractConnectionManager cm = backend.getConnectionManager(proc
00544 .getLogin());
00545 if (proc.isAutoCommit())
00546 {
00547 Connection c = null;
00548 try
00549 {
00550 c = cm.getConnection();
00551 }
00552 catch (UnreachableBackendException e1)
00553 {
00554 String backendName = backend.getName();
00555 logger.error(Translate.get(
00556 "loadbalancer.backend.disabling.unreachable", backendName));
00557 disableBackend(backend);
00558 backend = null;
00559 throw new SQLException(Translate.get(
00560 "loadbalancer.backend.unreacheable", backendName));
00561 }
00562
00563
00564 if (c == null)
00565 throw new SQLException(Translate.get(
00566 "loadbalancer.backend.no.connection", backend.getName()));
00567
00568
00569 int result;
00570 try
00571 {
00572 result = AbstractLoadBalancer.executeWriteStoredProcedureOnBackend(
00573 proc, backend, c);
00574 }
00575 catch (Exception e)
00576 {
00577 throw new SQLException(Translate.get(
00578 "loadbalancer.storedprocedure.failed.on.backend", new String[]{
00579 proc.getSQLShortForm(vdb.getSQLShortFormLength()),
00580 backend.getName(), e.getMessage()}));
00581 }
00582 finally
00583 {
00584 cm.releaseConnection(c);
00585 }
00586 return result;
00587 }
00588 else
00589 {
00590 Connection c = cm.retrieveConnection(proc.getTransactionId());
00591
00592
00593 if (c == null)
00594 throw new SQLException(Translate.get(
00595 "loadbalancer.unable.retrieve.connection", new String[]{
00596 String.valueOf(proc.getTransactionId()), backend.getName()}));
00597
00598
00599 try
00600 {
00601 return AbstractLoadBalancer.executeWriteStoredProcedureOnBackend(
00602 proc, backend, c);
00603 }
00604 catch (Exception e)
00605 {
00606 throw new SQLException(Translate.get(
00607 "loadbalancer.storedprocedure.failed.on.backend", new String[]{
00608 proc.getSQLShortForm(vdb.getSQLShortFormLength()),
00609 backend.getName(), e.getMessage()}));
00610 }
00611 }
00612 }
00613 catch (RuntimeException e)
00614 {
00615 String msg = Translate.get(
00616 "loadbalancer.storedprocedure.failed.on.backend", new String[]{
00617 proc.getSQLShortForm(vdb.getSQLShortFormLength()),
00618 backend.getName(), e.getMessage()});
00619 logger.fatal(msg, e);
00620 throw new SQLException(msg);
00621 }
00622 }
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634 public void begin(TransactionMarkerMetaData tm) throws SQLException
00635 {
00636 if (backend == null)
00637 throw new SQLException("No available backend to begin transaction "
00638 + tm.getTransactionId());
00639
00640
00641 if (backend.isDisabling())
00642 throw new SQLException(Translate.get("loadbalancer.backend.is.disabling",
00643 new String[]{"begin transaction " + tm.getTransactionId(),
00644 backend.getName()}));
00645
00646 try
00647 {
00648 Connection c = backend.getConnectionManager(tm.getLogin()).getConnection(
00649 tm.getTransactionId());
00650
00651 if (c == null)
00652 throw new SQLException(Translate.get(
00653 "loadbalancer.backend.no.connection", backend.getName()));
00654
00655 c.setAutoCommit(false);
00656 }
00657 catch (Exception e)
00658 {
00659 throw new SQLException("Begin of transaction " + tm.getTransactionId()
00660 + " failed on backend " + backend.getURL() + " (" + e + ")");
00661 }
00662 }
00663
00664
00665
00666
00667
00668
00669
00670 public void commit(TransactionMarkerMetaData tm) throws SQLException
00671 {
00672 if (backend == null)
00673 throw new SQLException("No available backend to commit transaction "
00674 + tm.getTransactionId());
00675
00676 try
00677 {
00678 AbstractConnectionManager cm = backend
00679 .getConnectionManager(tm.getLogin());
00680 Connection c = cm.retrieveConnection(tm.getTransactionId());
00681
00682 if (c == null)
00683 throw new SQLException("No connection found for transaction "
00684 + tm.getTransactionId());
00685
00686 try
00687 {
00688 c.commit();
00689 c.setAutoCommit(true);
00690 }
00691 catch (SQLException e)
00692 {
00693 throw new SQLException(Translate.get("loadbalancer.commit.failed",
00694 new String[]{String.valueOf(tm.getTransactionId()),
00695 backend.getName(), e.getMessage()}));
00696 }
00697 finally
00698 {
00699 cm.releaseConnection(tm.getTransactionId());
00700 }
00701 }
00702 catch (RuntimeException e)
00703 {
00704 String msg = Translate.get("loadbalancer.commit.failed", new String[]{
00705 String.valueOf(tm.getTransactionId()), backend.getName(),
00706 e.getMessage()});
00707 logger.fatal(msg, e);
00708 throw new SQLException(msg);
00709 }
00710 }
00711
00712
00713
00714
00715
00716
00717
00718 public void rollback(TransactionMarkerMetaData tm) throws SQLException
00719 {
00720 if (backend == null)
00721 throw new SQLException("No available backend to rollback transaction "
00722 + tm.getTransactionId());
00723
00724 try
00725 {
00726 AbstractConnectionManager cm = backend
00727 .getConnectionManager(tm.getLogin());
00728 Connection c = cm.retrieveConnection(tm.getTransactionId());
00729
00730 if (c == null)
00731 throw new SQLException("No connection found for transaction "
00732 + tm.getTransactionId());
00733
00734 try
00735 {
00736 c.rollback();
00737 c.setAutoCommit(true);
00738 }
00739 catch (SQLException e)
00740 {
00741 throw new SQLException(Translate.get("loadbalancer.rollback.failed",
00742 new String[]{String.valueOf(tm.getTransactionId()),
00743 backend.getName(), e.getMessage()}));
00744 }
00745 finally
00746 {
00747 cm.releaseConnection(tm.getTransactionId());
00748 }
00749 }
00750 catch (RuntimeException e)
00751 {
00752 String msg = Translate.get("loadbalancer.rollback.failed", new String[]{
00753 String.valueOf(tm.getTransactionId()), backend.getName(),
00754 e.getMessage()});
00755 logger.fatal(msg, e);
00756 throw new SQLException(msg);
00757 }
00758 }
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772 public void enableBackend(DatabaseBackend db, boolean writeEnabled)
00773 throws SQLException
00774 {
00775 if (backend != null)
00776 {
00777 if (backend.isReadEnabled())
00778 throw new SQLException(
00779 "SingleDB load balancer accepts only one backend and "
00780 + backend.getName() + " is already enabled. Skipping "
00781 + db.getName() + " initialization.");
00782 }
00783 backend = db;
00784 logger.info(Translate.get("loadbalancer.backend.enabling", db.getName()));
00785 if (!backend.isInitialized())
00786 backend.initializeConnections();
00787 backend.enableRead();
00788 if (writeEnabled)
00789 backend.enableWrite();
00790 }
00791
00792
00793
00794
00795
00796
00797
00798
00799 public void disableBackend(DatabaseBackend db) throws SQLException
00800 {
00801 if (backend.equals(db))
00802 {
00803 logger
00804 .info(Translate.get("loadbalancer.backend.disabling", db.getName()));
00805 backend.disable();
00806 if (backend.isInitialized())
00807 backend.finalizeConnections();
00808 backend = null;
00809 }
00810 else
00811 {
00812 String msg = "Trying to disable a non-existing backend " + db.getName();
00813 logger.warn(msg);
00814 throw new SQLException(msg);
00815 }
00816 }
00817
00818
00819
00820
00821
00822 public void setWeight(String name, int w) throws SQLException
00823 {
00824 throw new SQLException("Weight is not supported with this load balancer");
00825 }
00826
00827
00828
00829
00830
00831
00832
00833
00834
00835
00836 public String getInformation()
00837 {
00838 if (backend == null)
00839 return "SingleDB Request load balancer: !!!Warning!!! No enabled backend node found\n";
00840 else
00841 return "SingleDB Request load balancer using " + backend.getURL() + "\n";
00842 }
00843
00844
00845
00846
00847 public String getXmlImpl()
00848 {
00849 return "<" + DatabasesXmlTags.ELT_SingleDB + "/>";
00850 }
00851
00852 }