00001
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
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
00083 public SingleDB(
VirtualDatabase vdb)
throws SQLException
00084 {
00085
00086 super(vdb,
RAIDbLevels.SingleDB,
ParsingGranularities.NO_PARSING);
00087 }
00088
00089
00090
00091
00092
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
backend.disable();
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
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 backend.disable();
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
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 backend.disable();
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 =
new ControllerResultSet(request,
00372 executeUpdateRequestOnBackendWithKeys(request, backend, c),
00373 metadataCache);
00374 }
00375
catch (Exception e)
00376 {
00377
throw new SQLException(
Translate.get(
00378
"loadbalancer.request.failed.on.backend",
new String[]{
00379 request.getSQLShortForm(vdb.getSQLShortFormLength()),
00380 backend.getName(), e.getMessage()}));
00381 }
00382 finally
00383 {
00384 cm.releaseConnection(c);
00385 }
00386
return result;
00387 }
00388
else
00389 {
00390
00391 Connection c = cm.retrieveConnection(request.getTransactionId());
00392
00393
00394
if (c == null)
00395
throw new SQLException(
Translate.get(
00396
"loadbalancer.unable.retrieve.connection",
00397
new String[]{String.valueOf(request.getTransactionId()),
00398 backend.getName()}));
00399
00400
00401
try
00402 {
00403
return new ControllerResultSet(request,
00404 executeUpdateRequestOnBackendWithKeys(request, backend, c),
00405 metadataCache);
00406 }
00407
catch (Exception e)
00408 {
00409
throw new SQLException(Translate.get(
00410
"loadbalancer.request.failed.on.backend",
new String[]{
00411 request.getSQLShortForm(vdb.getSQLShortFormLength()),
00412 backend.getName(), e.getMessage()}));
00413 }
00414 finally
00415 {
00416 backend.removePendingRequest(request);
00417 }
00418 }
00419 }
00420
catch (RuntimeException e)
00421 {
00422 String msg = Translate.get(
"loadbalancer.request.failed.on.backend",
00423
new String[]{request.getSQLShortForm(vdb.getSQLShortFormLength()),
00424 backend.getName(), e.getMessage()});
00425 logger.fatal(msg, e);
00426
throw new SQLException(msg);
00427 }
00428 }
00429
00434 public ControllerResultSet execReadOnlyReadStoredProcedure(
00435
StoredProcedure proc,
MetadataCache metadataCache)
throws SQLException
00436 {
00437
return execReadStoredProcedure(proc, metadataCache);
00438 }
00439
00444 public ControllerResultSet execReadStoredProcedure(
StoredProcedure proc,
00445
MetadataCache metadataCache)
throws SQLException
00446 {
00447
if (backend == null)
00448
throw new SQLException(
00449
"No available backend to execute stored procedure " + proc.getId());
00450
00451
try
00452 {
00453
AbstractConnectionManager cm = backend.getConnectionManager(proc
00454 .getLogin());
00455
if (proc.isAutoCommit())
00456 {
00457 Connection c = null;
00458
try
00459 {
00460 c = cm.
getConnection();
00461 }
00462
catch (
UnreachableBackendException e1)
00463 {
00464 String backendName = backend.getName();
00465 logger.error(
Translate.get(
00466
"loadbalancer.backend.disabling.unreachable", backendName));
00467 backend.disable();
00468 backend = null;
00469
throw new SQLException(
Translate.get(
00470
"loadbalancer.backend.unreacheable", backendName));
00471 }
00472
00473
00474
if (c == null)
00475
throw new SQLException(
Translate.get(
00476
"loadbalancer.backend.no.connection", backend.getName()));
00477
00478
00479
ControllerResultSet rs = null;
00480
try
00481 {
00482 rs =
AbstractLoadBalancer.executeReadStoredProcedureOnBackend(proc,
00483 backend, c, metadataCache);
00484 }
00485
catch (Exception e)
00486 {
00487
throw new SQLException(
Translate.get(
00488
"loadbalancer.storedprocedure.failed.on.backend",
new String[]{
00489 proc.getSQLShortForm(vdb.getSQLShortFormLength()),
00490 backend.getName(), e.getMessage()}));
00491 }
00492 finally
00493 {
00494 cm.
releaseConnection(c);
00495 }
00496
return rs;
00497 }
00498
else
00499 {
00500 Connection c = cm.retrieveConnection(proc.getTransactionId());
00501
00502
00503
if (c == null)
00504
throw new SQLException(
Translate.get(
00505
"loadbalancer.unable.retrieve.connection",
new String[]{
00506 String.valueOf(proc.getTransactionId()), backend.getName()}));
00507
00508
00509
try
00510 {
00511
return AbstractLoadBalancer.executeReadStoredProcedureOnBackend(proc,
00512 backend, c, metadataCache);
00513 }
00514
catch (Exception e)
00515 {
00516
throw new SQLException(
Translate.get(
00517
"loadbalancer.storedprocedure.failed.on.backend",
new String[]{
00518 proc.getSQLShortForm(vdb.getSQLShortFormLength()),
00519 backend.getName(), e.getMessage()}));
00520 }
00521 }
00522 }
00523
catch (RuntimeException e)
00524 {
00525 String msg = Translate.get(
00526
"loadbalancer.storedprocedure.failed.on.backend",
new String[]{
00527 proc.getSQLShortForm(vdb.getSQLShortFormLength()),
00528 backend.getName(), e.getMessage()});
00529 logger.fatal(msg, e);
00530
throw new SQLException(msg);
00531 }
00532 }
00533
00537 public int execWriteStoredProcedure(
StoredProcedure proc)
throws SQLException
00538 {
00539
if (backend == null)
00540
throw new SQLException(
00541
"No available backend to execute stored procedure " + proc.getId());
00542
00543
try
00544 {
00545
AbstractConnectionManager cm = backend.getConnectionManager(proc
00546 .getLogin());
00547
if (proc.isAutoCommit())
00548 {
00549 Connection c = null;
00550
try
00551 {
00552 c = cm.
getConnection();
00553 }
00554
catch (
UnreachableBackendException e1)
00555 {
00556 String backendName = backend.getName();
00557 logger.error(
Translate.get(
00558
"loadbalancer.backend.disabling.unreachable", backendName));
00559 backend.disable();
00560 backend = null;
00561
throw new SQLException(
Translate.get(
00562
"loadbalancer.backend.unreacheable", backendName));
00563 }
00564
00565
00566
if (c == null)
00567
throw new SQLException(
Translate.get(
00568
"loadbalancer.backend.no.connection", backend.getName()));
00569
00570
00571
int result;
00572
try
00573 {
00574 result =
AbstractLoadBalancer.executeWriteStoredProcedureOnBackend(
00575 proc, backend, c);
00576 }
00577
catch (Exception e)
00578 {
00579
throw new SQLException(
Translate.get(
00580
"loadbalancer.storedprocedure.failed.on.backend",
new String[]{
00581 proc.getSQLShortForm(vdb.getSQLShortFormLength()),
00582 backend.getName(), e.getMessage()}));
00583 }
00584 finally
00585 {
00586 cm.
releaseConnection(c);
00587 }
00588
return result;
00589 }
00590
else
00591 {
00592 Connection c = cm.retrieveConnection(proc.getTransactionId());
00593
00594
00595
if (c == null)
00596
throw new SQLException(
Translate.get(
00597
"loadbalancer.unable.retrieve.connection",
new String[]{
00598 String.valueOf(proc.getTransactionId()), backend.getName()}));
00599
00600
00601
try
00602 {
00603
return AbstractLoadBalancer.executeWriteStoredProcedureOnBackend(
00604 proc, backend, c);
00605 }
00606
catch (Exception e)
00607 {
00608
throw new SQLException(
Translate.get(
00609
"loadbalancer.storedprocedure.failed.on.backend",
new String[]{
00610 proc.getSQLShortForm(vdb.getSQLShortFormLength()),
00611 backend.getName(), e.getMessage()}));
00612 }
00613 }
00614 }
00615
catch (RuntimeException e)
00616 {
00617 String msg = Translate.get(
00618
"loadbalancer.storedprocedure.failed.on.backend",
new String[]{
00619 proc.getSQLShortForm(vdb.getSQLShortFormLength()),
00620 backend.getName(), e.getMessage()});
00621 logger.fatal(msg, e);
00622
throw new SQLException(msg);
00623 }
00624 }
00625
00626
00627
00628
00629
00636 public void begin(
TransactionMarkerMetaData tm)
throws SQLException
00637 {
00638
if (backend == null)
00639
throw new SQLException(
"No available backend to begin transaction "
00640 + tm.getTransactionId());
00641
00642
00643
if (backend.isDisabling())
00644
throw new SQLException(
Translate.get(
"loadbalancer.backend.is.disabling",
00645
new String[]{
"begin transaction " + tm.getTransactionId(),
00646 backend.getName()}));
00647
00648
try
00649 {
00650 Connection c = backend.getConnectionManager(tm.getLogin()).getConnection(
00651 tm.getTransactionId());
00652
00653
if (c == null)
00654
throw new SQLException(
Translate.get(
00655
"loadbalancer.backend.no.connection", backend.getName()));
00656
00657 c.setAutoCommit(
false);
00658 }
00659
catch (Exception e)
00660 {
00661
throw new SQLException(
"Begin of transaction " + tm.getTransactionId()
00662 +
" failed on backend " + backend.getURL() +
" (" + e +
")");
00663 }
00664 }
00665
00672 public void commit(
TransactionMarkerMetaData tm)
throws SQLException
00673 {
00674
if (backend == null)
00675
throw new SQLException(
"No available backend to commit transaction "
00676 + tm.getTransactionId());
00677
00678
try
00679 {
00680
AbstractConnectionManager cm = backend
00681 .getConnectionManager(tm.getLogin());
00682 Connection c = cm.
retrieveConnection(tm.getTransactionId());
00683
00684
if (c == null)
00685
throw new SQLException(
"No connection found for transaction "
00686 + tm.getTransactionId());
00687
00688
try
00689 {
00690 c.commit();
00691 c.setAutoCommit(
true);
00692 }
00693
catch (SQLException e)
00694 {
00695
throw new SQLException(
Translate.get(
"loadbalancer.commit.failed",
00696
new String[]{String.valueOf(tm.getTransactionId()),
00697 backend.getName(), e.getMessage()}));
00698 }
00699 finally
00700 {
00701 cm.releaseConnection(tm.getTransactionId());
00702 }
00703 }
00704
catch (RuntimeException e)
00705 {
00706 String msg =
Translate.get(
"loadbalancer.commit.failed",
new String[]{
00707 String.valueOf(tm.getTransactionId()), backend.getName(),
00708 e.getMessage()});
00709 logger.fatal(msg, e);
00710
throw new SQLException(msg);
00711 }
00712 }
00713
00720 public void rollback(
TransactionMarkerMetaData tm)
throws SQLException
00721 {
00722
if (backend == null)
00723
throw new SQLException(
"No available backend to rollback transaction "
00724 + tm.getTransactionId());
00725
00726
try
00727 {
00728
AbstractConnectionManager cm = backend
00729 .getConnectionManager(tm.getLogin());
00730 Connection c = cm.
retrieveConnection(tm.getTransactionId());
00731
00732
if (c == null)
00733
throw new SQLException(
"No connection found for transaction "
00734 + tm.getTransactionId());
00735
00736
try
00737 {
00738 c.rollback();
00739 c.setAutoCommit(
true);
00740 }
00741
catch (SQLException e)
00742 {
00743
throw new SQLException(
Translate.get(
"loadbalancer.rollback.failed",
00744
new String[]{String.valueOf(tm.getTransactionId()),
00745 backend.getName(), e.getMessage()}));
00746 }
00747 finally
00748 {
00749 cm.releaseConnection(tm.getTransactionId());
00750 }
00751 }
00752
catch (RuntimeException e)
00753 {
00754 String msg =
Translate.get(
"loadbalancer.rollback.failed",
new String[]{
00755 String.valueOf(tm.getTransactionId()), backend.getName(),
00756 e.getMessage()});
00757 logger.fatal(msg, e);
00758
throw new SQLException(msg);
00759 }
00760 }
00761
00762
00763
00764
00765
00774 public void enableBackend(DatabaseBackend db,
boolean writeEnabled)
00775
throws SQLException
00776 {
00777
if (backend != null)
00778 {
00779
if (backend.isReadEnabled())
00780
throw new SQLException(
00781
"SingleDB load balancer accepts only one backend and "
00782 + backend.getName() +
" is already enabled. Skipping "
00783 + db.getName() +
" initialization.");
00784 }
00785 backend = db;
00786 logger.info(
Translate.get(
"loadbalancer.backend.enabling", db.getName()));
00787
if (!backend.isInitialized())
00788 backend.initializeConnections();
00789 backend.enableRead();
00790
if (writeEnabled)
00791 backend.enableWrite();
00792 }
00793
00801 public void disableBackend(DatabaseBackend db)
throws SQLException
00802 {
00803
if (backend.equals(db))
00804 {
00805 logger
00806 .info(
Translate.get(
"loadbalancer.backend.disabling", db.getName()));
00807 backend.disable();
00808
if (backend.isInitialized())
00809 backend.finalizeConnections();
00810 backend = null;
00811 }
00812
else
00813 {
00814 String msg =
"Trying to disable a non-existing backend " + db.getName();
00815 logger.warn(msg);
00816
throw new SQLException(msg);
00817 }
00818 }
00819
00824 public void setWeight(String name,
int w)
throws SQLException
00825 {
00826
throw new SQLException(
"Weight is not supported with this load balancer");
00827 }
00828
00829
00830
00831
00832
00838 public String getInformation()
00839 {
00840
if (backend == null)
00841
return "SingleDB Request load balancer: !!!Warning!!! No enabled backend node found\n";
00842
else
00843
return "SingleDB Request load balancer using " + backend.getURL() +
"\n";
00844 }
00845
00849 public String getXmlImpl()
00850 {
00851
return "<" +
DatabasesXmlTags.ELT_SingleDB +
"/>";
00852 }
00853
00854 }