0001: /**
0002: * Sequoia: Database clustering technology.
0003: * Copyright (C) 2002-2004 French National Institute For Research In Computer
0004: * Science And Control (INRIA).
0005: * Copyright (C) 2005 AmicoSoft, Inc. dba Emic Networks
0006: * Contact: sequoia@continuent.org
0007: *
0008: * Licensed under the Apache License, Version 2.0 (the "License");
0009: * you may not use this file except in compliance with the License.
0010: * You may obtain a copy of the License at
0011: *
0012: * http://www.apache.org/licenses/LICENSE-2.0
0013: *
0014: * Unless required by applicable law or agreed to in writing, software
0015: * distributed under the License is distributed on an "AS IS" BASIS,
0016: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0017: * See the License for the specific language governing permissions and
0018: * limitations under the License.
0019: *
0020: * Initial developer(s): Emmanuel Cecchet.
0021: * Contributor(s): Vadim Kassin, Jaco Swart, Jean-Bernard van Zuylen.
0022: */package org.continuent.sequoia.controller.loadbalancer.singledb;
0023:
0024: import java.sql.Connection;
0025: import java.sql.SQLException;
0026: import java.sql.Savepoint;
0027:
0028: import org.continuent.sequoia.common.exceptions.BadConnectionException;
0029: import org.continuent.sequoia.common.exceptions.NoMoreBackendException;
0030: import org.continuent.sequoia.common.exceptions.UnreachableBackendException;
0031: import org.continuent.sequoia.common.i18n.Translate;
0032: import org.continuent.sequoia.common.log.Trace;
0033: import org.continuent.sequoia.common.xml.DatabasesXmlTags;
0034: import org.continuent.sequoia.controller.backend.DatabaseBackend;
0035: import org.continuent.sequoia.controller.backend.result.ControllerResultSet;
0036: import org.continuent.sequoia.controller.backend.result.ExecuteResult;
0037: import org.continuent.sequoia.controller.backend.result.ExecuteUpdateResult;
0038: import org.continuent.sequoia.controller.backend.result.GeneratedKeysResult;
0039: import org.continuent.sequoia.controller.cache.metadata.MetadataCache;
0040: import org.continuent.sequoia.controller.connection.AbstractConnectionManager;
0041: import org.continuent.sequoia.controller.connection.PooledConnection;
0042: import org.continuent.sequoia.controller.loadbalancer.AbstractLoadBalancer;
0043: import org.continuent.sequoia.controller.loadbalancer.AllBackendsFailedException;
0044: import org.continuent.sequoia.controller.loadbalancer.policies.WaitForCompletionPolicy;
0045: import org.continuent.sequoia.controller.requestmanager.RAIDbLevels;
0046: import org.continuent.sequoia.controller.requestmanager.TransactionMetaData;
0047: import org.continuent.sequoia.controller.requests.AbstractRequest;
0048: import org.continuent.sequoia.controller.requests.AbstractWriteRequest;
0049: import org.continuent.sequoia.controller.requests.ParsingGranularities;
0050: import org.continuent.sequoia.controller.requests.SelectRequest;
0051: import org.continuent.sequoia.controller.requests.StoredProcedure;
0052: import org.continuent.sequoia.controller.requests.UnknownReadRequest;
0053: import org.continuent.sequoia.controller.virtualdatabase.VirtualDatabase;
0054:
0055: /**
0056: * Single Database request load balancer.
0057: * <p>
0058: * The requests coming from the request controller are directly forwarded to the
0059: * single backend. This load balancer does not support multiple backends and
0060: * does not update the recovery log (it is not meant to be used with a recovery
0061: * log).
0062: *
0063: * @author <a href="mailto:Emmanuel.Cecchet@inria.fr">Emmanuel Cecchet </a>
0064: * @author <a href="mailto:vadim@kase.kz">Vadim Kassin </a>
0065: * @author <a href="mailto:jaco.swart@iblocks.co.uk">Jaco Swart </a>
0066: * @author <a href="mailto:jbvanzuylen@transwide.com">Jean-Bernard van Zuylen
0067: * </a>
0068: * @version 1.0
0069: */
0070: public class SingleDB extends AbstractLoadBalancer {
0071: //
0072: // How the code is organized?
0073: // 1. Member variables
0074: // 2. Constructor(s)
0075: // 3. Request handling
0076: // 4. Transaction handling
0077: // 5. Backend management
0078: // 6. Debug/Monitoring
0079: //
0080:
0081: private DatabaseBackend backend;
0082:
0083: private static Trace logger = Trace
0084: .getLogger("org.continuent.sequoia.controller.loadbalancer.SingleDB");
0085:
0086: static Trace endUserLogger = Trace
0087: .getLogger("org.continuent.sequoia.enduser");
0088:
0089: /*
0090: * Constructors
0091: */
0092:
0093: /**
0094: * Creates a new <code>SingleDB</code> instance.
0095: *
0096: * @param vdb the <code>VirtualDatabase</code> this load balancer belongs to
0097: * @throws Exception if there is not exactly one backend attached to the
0098: * <code>VirtualDatabase</code>
0099: */
0100: public SingleDB(VirtualDatabase vdb) throws Exception {
0101: // We don't need to parse the requests, just send them to the backend
0102: super (vdb, RAIDbLevels.SingleDB,
0103: ParsingGranularities.NO_PARSING);
0104: this .waitForCompletionPolicy = new WaitForCompletionPolicy(
0105: WaitForCompletionPolicy.ALL, false,
0106: ParsingGranularities.NO_PARSING);
0107: }
0108:
0109: /*
0110: * Request Handling
0111: */
0112:
0113: /**
0114: * Performs a read request. It is up to the implementation to choose to which
0115: * backend node(s) this request should be sent.
0116: *
0117: * @param request an <code>SelectRequest</code>
0118: * @param metadataCache MetadataCache (null if none)
0119: * @return the corresponding <code>java.sql.ResultSet</code>
0120: * @exception SQLException if an error occurs
0121: */
0122: public ControllerResultSet statementExecuteQuery(
0123: SelectRequest request, MetadataCache metadataCache)
0124: throws SQLException {
0125: if (backend == null)
0126: throw new NoMoreBackendException(Translate.get(
0127: "loadbalancer.execute.no.backend.available",
0128: request.getId()));
0129:
0130: try {
0131: AbstractConnectionManager cm = backend
0132: .getConnectionManager(request.getLogin());
0133: if (request.isAutoCommit()) {
0134: ControllerResultSet rs = null;
0135: boolean badConnection;
0136: do {
0137: badConnection = false;
0138: // Use a connection just for this request
0139: PooledConnection c = null;
0140: try {
0141: c = cm.retrieveConnectionInAutoCommit(request);
0142: } catch (UnreachableBackendException e1) {
0143: String backendName = backend.getName();
0144: String msg = Translate
0145: .get(
0146: "loadbalancer.backend.disabling.unreachable",
0147: backendName);
0148: logger.error(msg);
0149: endUserLogger.error(msg);
0150: disableBackend(backend, true);
0151: backend = null;
0152: throw new SQLException(Translate.get(
0153: "loadbalancer.backend.unreacheable",
0154: backendName));
0155: }
0156:
0157: // Sanity check
0158: if (c == null)
0159: throw new SQLException(Translate.get(
0160: "loadbalancer.backend.no.connection",
0161: backend.getName()));
0162:
0163: // Execute Query
0164: try {
0165: rs = executeStatementExecuteQueryOnBackend(
0166: request, backend, null, c
0167: .getConnection(), metadataCache);
0168: cm.releaseConnectionInAutoCommit(request, c);
0169: } catch (SQLException e) {
0170: cm.releaseConnectionInAutoCommit(request, c);
0171: throw new SQLException(
0172: Translate
0173: .get(
0174: "loadbalancer.request.failed.on.backend",
0175: new String[] {
0176: request
0177: .getSqlShortForm(vdb
0178: .getSqlShortFormLength()),
0179: backend
0180: .getName(),
0181: e.getMessage() }));
0182: } catch (BadConnectionException e) { // Get rid of the bad connection
0183: cm.deleteConnection(c);
0184: badConnection = true;
0185: } catch (Throwable e) {
0186: cm.releaseConnectionInAutoCommit(request, c);
0187: throw new SQLException(
0188: Translate
0189: .get(
0190: "loadbalancer.request.failed.on.backend",
0191: new String[] {
0192: request
0193: .getSqlShortForm(vdb
0194: .getSqlShortFormLength()),
0195: backend
0196: .getName(),
0197: e.getMessage() }));
0198: }
0199: } while (badConnection);
0200: return rs;
0201: } else {
0202: long tid = request.getTransactionId();
0203: // Re-use the connection used by this transaction
0204: PooledConnection c = cm
0205: .retrieveConnectionForTransaction(tid);
0206:
0207: // Sanity check
0208: if (c == null)
0209: throw new SQLException(Translate.get(
0210: "loadbalancer.unable.retrieve.connection",
0211: new String[] { String.valueOf(tid),
0212: backend.getName() }));
0213:
0214: // Execute Query
0215: ControllerResultSet rs = null;
0216: try {
0217: rs = executeStatementExecuteQueryOnBackend(request,
0218: backend, null, c.getConnection(),
0219: metadataCache);
0220: } catch (SQLException e) {
0221: throw new SQLException(
0222: Translate
0223: .get(
0224: "loadbalancer.request.failed.on.backend",
0225: new String[] {
0226: request
0227: .getSqlShortForm(vdb
0228: .getSqlShortFormLength()),
0229: backend.getName(),
0230: e.getMessage() }));
0231: } catch (BadConnectionException e) { // Get rid of the bad connection
0232: cm.deleteConnection(tid);
0233: throw new SQLException(Translate
0234: .get("loadbalancer.connection.failed",
0235: new String[] { String.valueOf(tid),
0236: backend.getName(),
0237: e.getMessage() }));
0238: } catch (Throwable e) {
0239: throw new SQLException(
0240: Translate
0241: .get(
0242: "loadbalancer.request.failed.on.backend",
0243: new String[] {
0244: request
0245: .getSqlShortForm(vdb
0246: .getSqlShortFormLength()),
0247: backend.getName(),
0248: e.getMessage() }));
0249: }
0250: return rs;
0251: }
0252: } catch (RuntimeException e) {
0253: String msg = "Request '"
0254: + request.getSqlShortForm(vdb
0255: .getSqlShortFormLength())
0256: + "' failed on backend " + backend.getURL() + " ("
0257: + e + ")";
0258: logger.fatal(msg, e);
0259: throw new SQLException(msg);
0260: }
0261: }
0262:
0263: /**
0264: * Performs a write request on the backend.
0265: *
0266: * @param request an <code>AbstractWriteRequest</code>
0267: * @return number of rows affected by the request
0268: * @exception SQLException if an error occurs
0269: */
0270: public ExecuteUpdateResult statementExecuteUpdate(
0271: AbstractWriteRequest request) throws SQLException {
0272: if (backend == null)
0273: throw new NoMoreBackendException(Translate.get(
0274: "loadbalancer.execute.no.backend.available",
0275: request.getId()));
0276:
0277: try {
0278: AbstractConnectionManager cm = backend
0279: .getConnectionManager(request.getLogin());
0280: if (request.isAutoCommit()) {
0281: // We do not execute request outside the already open transactions if we
0282: // are disabling the backend.
0283: if (!backend.canAcceptTasks(request))
0284: throw new SQLException(Translate.get(
0285: "loadbalancer.backend.is.disabling",
0286: new String[] {
0287: request.getSqlShortForm(vdb
0288: .getSqlShortFormLength()),
0289: backend.getName() }));
0290:
0291: // Use a connection just for this request
0292: PooledConnection c = null;
0293: try {
0294: c = cm.retrieveConnectionInAutoCommit(request);
0295: } catch (UnreachableBackendException e1) {
0296: String backendName = backend.getName();
0297: String msg = Translate
0298: .get(
0299: "loadbalancer.backend.disabling.unreachable",
0300: backendName);
0301: logger.error(msg);
0302: endUserLogger.error(msg);
0303: disableBackend(backend, true);
0304: backend = null;
0305: throw new SQLException(Translate.get(
0306: "loadbalancer.backend.unreacheable",
0307: backendName));
0308: }
0309:
0310: // Sanity check
0311: if (c == null)
0312: throw new SQLException(Translate.get(
0313: "loadbalancer.backend.no.connection",
0314: backend.getName()));
0315:
0316: // Execute Query
0317: ExecuteUpdateResult result;
0318: try {
0319: result = executeStatementExecuteUpdateOnBackend(
0320: request, backend, null, c);
0321: } catch (Exception e) {
0322: throw new SQLException(
0323: Translate
0324: .get(
0325: "loadbalancer.request.failed.on.backend",
0326: new String[] {
0327: request
0328: .getSqlShortForm(vdb
0329: .getSqlShortFormLength()),
0330: backend.getName(),
0331: e.getMessage() }));
0332: } finally {
0333: cm.releaseConnectionInAutoCommit(request, c);
0334: }
0335: return result;
0336: } else { // Re-use the connection used by this transaction
0337: PooledConnection c = cm
0338: .retrieveConnectionForTransaction(request
0339: .getTransactionId());
0340:
0341: // Sanity check
0342: if (c == null)
0343: throw new SQLException(Translate.get(
0344: "loadbalancer.unable.retrieve.connection",
0345: new String[] {
0346: String.valueOf(request
0347: .getTransactionId()),
0348: backend.getName() }));
0349:
0350: // Execute Query
0351: try {
0352: ExecuteUpdateResult result = executeStatementExecuteUpdateOnBackend(
0353: request, backend, null, c);
0354: return result;
0355: } catch (Exception e) {
0356: throw new SQLException(
0357: Translate
0358: .get(
0359: "loadbalancer.request.failed.on.backend",
0360: new String[] {
0361: request
0362: .getSqlShortForm(vdb
0363: .getSqlShortFormLength()),
0364: backend.getName(),
0365: e.getMessage() }));
0366: }
0367: }
0368: } catch (RuntimeException e) {
0369: String msg = Translate.get(
0370: "loadbalancer.request.failed.on.backend",
0371: new String[] {
0372: request.getSqlShortForm(vdb
0373: .getSqlShortFormLength()),
0374: backend.getName(), e.getMessage() });
0375: endUserLogger.fatal(msg);
0376: logger.fatal(msg, e);
0377: throw new SQLException(msg);
0378: }
0379: }
0380:
0381: /**
0382: * @see AbstractLoadBalancer#statementExecuteUpdateWithKeys(AbstractWriteRequest,
0383: * MetadataCache)
0384: */
0385: public GeneratedKeysResult statementExecuteUpdateWithKeys(
0386: AbstractWriteRequest request, MetadataCache metadataCache)
0387: throws SQLException {
0388: if (backend == null)
0389: throw new NoMoreBackendException(Translate.get(
0390: "loadbalancer.execute.no.backend.available",
0391: request.getId()));
0392:
0393: if (!backend.getDriverCompliance().supportGetGeneratedKeys())
0394: throw new SQLException(
0395: Translate
0396: .get(
0397: "loadbalancer.backend.autogeneratedkeys.unsupported",
0398: backend.getName()));
0399:
0400: try {
0401: AbstractConnectionManager cm = backend
0402: .getConnectionManager(request.getLogin());
0403: if (request.isAutoCommit()) {
0404: // We do not execute request outside the already open transactions if we
0405: // are disabling the backend.
0406: if (!backend.canAcceptTasks(request))
0407: throw new SQLException(Translate.get(
0408: "loadbalancer.backend.is.disabling",
0409: new String[] {
0410: request.getSqlShortForm(vdb
0411: .getSqlShortFormLength()),
0412: backend.getName() }));
0413:
0414: // Use a connection just for this request
0415: PooledConnection c = null;
0416: try {
0417: c = cm.retrieveConnectionInAutoCommit(request);
0418: } catch (UnreachableBackendException e1) {
0419: String backendName = backend.getName();
0420: String msg = Translate
0421: .get(
0422: "loadbalancer.backend.disabling.unreachable",
0423: backendName);
0424: logger.error(msg);
0425: endUserLogger.error(msg);
0426: disableBackend(backend, true);
0427: backend = null;
0428: throw new SQLException(Translate.get(
0429: "loadbalancer.backend.unreacheable",
0430: backendName));
0431: }
0432:
0433: // Sanity check
0434: if (c == null)
0435: throw new SQLException(Translate.get(
0436: "loadbalancer.backend.no.connection",
0437: backend.getName()));
0438:
0439: // Execute Query
0440: GeneratedKeysResult result;
0441: try {
0442: result = executeStatementExecuteUpdateWithKeysOnBackend(
0443: request, backend, null, c, metadataCache);
0444: } catch (Exception e) {
0445: throw new SQLException(
0446: Translate
0447: .get(
0448: "loadbalancer.request.failed.on.backend",
0449: new String[] {
0450: request
0451: .getSqlShortForm(vdb
0452: .getSqlShortFormLength()),
0453: backend.getName(),
0454: e.getMessage() }));
0455: } finally {
0456: cm.releaseConnectionInAutoCommit(request, c);
0457: }
0458: return result;
0459: } else {
0460: // Re-use the connection used by this transaction
0461: PooledConnection c = cm
0462: .retrieveConnectionForTransaction(request
0463: .getTransactionId());
0464:
0465: // Sanity check
0466: if (c == null)
0467: throw new SQLException(Translate.get(
0468: "loadbalancer.unable.retrieve.connection",
0469: new String[] {
0470: String.valueOf(request
0471: .getTransactionId()),
0472: backend.getName() }));
0473:
0474: // Execute Query
0475: try {
0476: GeneratedKeysResult result = executeStatementExecuteUpdateWithKeysOnBackend(
0477: request, backend, null, c, metadataCache);
0478: return result;
0479: } catch (Exception e) {
0480: throw new SQLException(
0481: Translate
0482: .get(
0483: "loadbalancer.request.failed.on.backend",
0484: new String[] {
0485: request
0486: .getSqlShortForm(vdb
0487: .getSqlShortFormLength()),
0488: backend.getName(),
0489: e.getMessage() }));
0490: } finally {
0491: backend.removePendingRequest(request);
0492: }
0493: }
0494: } catch (RuntimeException e) {
0495: String msg = Translate.get(
0496: "loadbalancer.request.failed.on.backend",
0497: new String[] {
0498: request.getSqlShortForm(vdb
0499: .getSqlShortFormLength()),
0500: backend.getName(), e.getMessage() });
0501: logger.fatal(msg, e);
0502: endUserLogger.fatal(msg);
0503: throw new SQLException(msg);
0504: }
0505: }
0506:
0507: /**
0508: * @see org.continuent.sequoia.controller.loadbalancer.AbstractLoadBalancer#statementExecute(org.continuent.sequoia.controller.requests.AbstractRequest,
0509: * org.continuent.sequoia.controller.cache.metadata.MetadataCache)
0510: */
0511: public ExecuteResult statementExecute(AbstractRequest request,
0512: MetadataCache metadataCache) throws SQLException {
0513: if (backend == null)
0514: throw new SQLException(
0515: "No available backend to execute request "
0516: + request.getId());
0517:
0518: try {
0519: AbstractConnectionManager cm = backend
0520: .getConnectionManager(request.getLogin());
0521: if (request.isAutoCommit()) { // Use a connection just for this request
0522: PooledConnection c = null;
0523: try {
0524: c = cm.retrieveConnectionInAutoCommit(request);
0525: } catch (UnreachableBackendException e1) {
0526: String backendName = backend.getName();
0527: String msg = Translate
0528: .get(
0529: "loadbalancer.backend.disabling.unreachable",
0530: backendName);
0531: logger.error(msg);
0532: endUserLogger.error(msg);
0533: disableBackend(backend, true);
0534: backend = null;
0535: throw new SQLException(Translate.get(
0536: "loadbalancer.backend.unreacheable",
0537: backendName));
0538: }
0539:
0540: // Sanity check
0541: if (c == null)
0542: throw new SQLException(Translate.get(
0543: "loadbalancer.backend.no.connection",
0544: backend.getName()));
0545:
0546: // Execute Query
0547: ExecuteResult rs = null;
0548: try {
0549: rs = AbstractLoadBalancer
0550: .executeStatementExecuteOnBackend(request,
0551: backend, null, c, metadataCache);
0552: } catch (Exception e) {
0553: throw new SQLException(
0554: Translate
0555: .get(
0556: "loadbalancer.request.failed.on.backend",
0557: new String[] {
0558: request
0559: .getSqlShortForm(vdb
0560: .getSqlShortFormLength()),
0561: backend.getName(),
0562: e.getMessage() }));
0563: } finally {
0564: cm.releaseConnectionInAutoCommit(request, c);
0565: }
0566: return rs;
0567: } else { // Re-use the connection used by this transaction
0568: PooledConnection c = cm
0569: .retrieveConnectionForTransaction(request
0570: .getTransactionId());
0571:
0572: // Sanity check
0573: if (c == null)
0574: throw new SQLException(Translate.get(
0575: "loadbalancer.unable.retrieve.connection",
0576: new String[] {
0577: String.valueOf(request
0578: .getTransactionId()),
0579: backend.getName() }));
0580:
0581: // Execute Query
0582: try {
0583: return AbstractLoadBalancer
0584: .executeStatementExecuteOnBackend(request,
0585: backend, null, c, metadataCache);
0586: } catch (Exception e) {
0587: throw new SQLException(
0588: Translate
0589: .get(
0590: "loadbalancer.request.failed.on.backend",
0591: new String[] {
0592: request
0593: .getSqlShortForm(vdb
0594: .getSqlShortFormLength()),
0595: backend.getName(),
0596: e.getMessage() }));
0597: }
0598: }
0599: } catch (RuntimeException e) {
0600: String msg = Translate.get(
0601: "loadbalancer.request.failed.on.backend",
0602: new String[] {
0603: request.getSqlShortForm(vdb
0604: .getSqlShortFormLength()),
0605: backend.getName(), e.getMessage() });
0606: logger.fatal(msg, e);
0607: endUserLogger.fatal(msg);
0608: throw new SQLException(msg);
0609: }
0610: }
0611:
0612: /**
0613: * @see org.continuent.sequoia.controller.loadbalancer.AbstractLoadBalancer#readOnlyCallableStatementExecuteQuery(StoredProcedure,
0614: * MetadataCache)
0615: */
0616: public ControllerResultSet readOnlyCallableStatementExecuteQuery(
0617: StoredProcedure proc, MetadataCache metadataCache)
0618: throws SQLException {
0619: return callableStatementExecuteQuery(proc, metadataCache);
0620: }
0621:
0622: /**
0623: * @see org.continuent.sequoia.controller.loadbalancer.AbstractLoadBalancer#readOnlyCallableStatementExecute(org.continuent.sequoia.controller.requests.StoredProcedure,
0624: * org.continuent.sequoia.controller.cache.metadata.MetadataCache)
0625: */
0626: public ExecuteResult readOnlyCallableStatementExecute(
0627: StoredProcedure proc, MetadataCache metadataCache)
0628: throws SQLException {
0629: return callableStatementExecute(proc, metadataCache);
0630: }
0631:
0632: /**
0633: * @see org.continuent.sequoia.controller.loadbalancer.AbstractLoadBalancer#callableStatementExecuteQuery(StoredProcedure,
0634: * MetadataCache)
0635: */
0636: public ControllerResultSet callableStatementExecuteQuery(
0637: StoredProcedure proc, MetadataCache metadataCache)
0638: throws SQLException {
0639: if (backend == null)
0640: throw new SQLException(
0641: "No available backend to execute stored procedure "
0642: + proc.getId());
0643:
0644: try {
0645: AbstractConnectionManager cm = backend
0646: .getConnectionManager(proc.getLogin());
0647: if (proc.isAutoCommit()) { // Use a connection just for this request
0648: PooledConnection c = null;
0649: try {
0650: c = cm.retrieveConnectionInAutoCommit(proc);
0651: } catch (UnreachableBackendException e1) {
0652: String backendName = backend.getName();
0653: String msg = Translate
0654: .get(
0655: "loadbalancer.backend.disabling.unreachable",
0656: backendName);
0657: logger.error(msg);
0658: endUserLogger.error(msg);
0659: disableBackend(backend, true);
0660: backend = null;
0661: throw new SQLException(Translate.get(
0662: "loadbalancer.backend.unreacheable",
0663: backendName));
0664: }
0665:
0666: // Sanity check
0667: if (c == null)
0668: throw new SQLException(Translate.get(
0669: "loadbalancer.backend.no.connection",
0670: backend.getName()));
0671:
0672: // Execute Query
0673: ControllerResultSet rs = null;
0674: try {
0675: rs = AbstractLoadBalancer
0676: .executeCallableStatementExecuteQueryOnBackend(
0677: proc, backend, null, c
0678: .getConnection(),
0679: metadataCache);
0680: } catch (Exception e) {
0681: throw new SQLException(
0682: Translate
0683: .get(
0684: "loadbalancer.storedprocedure.failed.on.backend",
0685: new String[] {
0686: proc
0687: .getSqlShortForm(vdb
0688: .getSqlShortFormLength()),
0689: backend.getName(),
0690: e.getMessage() }));
0691: } finally {
0692: cm.releaseConnectionInAutoCommit(proc, c);
0693: }
0694: return rs;
0695: } else { // Re-use the connection used by this transaction
0696: PooledConnection c = cm
0697: .retrieveConnectionForTransaction(proc
0698: .getTransactionId());
0699:
0700: // Sanity check
0701: if (c == null)
0702: throw new SQLException(Translate.get(
0703: "loadbalancer.unable.retrieve.connection",
0704: new String[] {
0705: String.valueOf(proc
0706: .getTransactionId()),
0707: backend.getName() }));
0708:
0709: // Execute Query
0710: try {
0711: ControllerResultSet result = AbstractLoadBalancer
0712: .executeCallableStatementExecuteQueryOnBackend(
0713: proc, backend, null, c
0714: .getConnection(),
0715: metadataCache);
0716: return result;
0717: } catch (Exception e) {
0718: throw new SQLException(
0719: Translate
0720: .get(
0721: "loadbalancer.storedprocedure.failed.on.backend",
0722: new String[] {
0723: proc
0724: .getSqlShortForm(vdb
0725: .getSqlShortFormLength()),
0726: backend.getName(),
0727: e.getMessage() }));
0728: }
0729: }
0730: } catch (RuntimeException e) {
0731: String msg = Translate.get(
0732: "loadbalancer.storedprocedure.failed.on.backend",
0733: new String[] {
0734: proc.getSqlShortForm(vdb
0735: .getSqlShortFormLength()),
0736: backend.getName(), e.getMessage() });
0737: logger.fatal(msg, e);
0738: endUserLogger.fatal(msg);
0739: throw new SQLException(msg);
0740: }
0741: }
0742:
0743: /**
0744: * @see org.continuent.sequoia.controller.loadbalancer.AbstractLoadBalancer#callableStatementExecuteUpdate(org.continuent.sequoia.controller.requests.StoredProcedure)
0745: */
0746: public ExecuteUpdateResult callableStatementExecuteUpdate(
0747: StoredProcedure proc) throws SQLException {
0748: if (backend == null)
0749: throw new SQLException(
0750: "No available backend to execute stored procedure "
0751: + proc.getId());
0752:
0753: try {
0754: AbstractConnectionManager cm = backend
0755: .getConnectionManager(proc.getLogin());
0756: if (proc.isAutoCommit()) { // Use a connection just for this request
0757: PooledConnection c = null;
0758: try {
0759: c = cm.retrieveConnectionInAutoCommit(proc);
0760: } catch (UnreachableBackendException e1) {
0761: String backendName = backend.getName();
0762: String msg = Translate
0763: .get(
0764: "loadbalancer.backend.disabling.unreachable",
0765: backendName);
0766: logger.error(msg);
0767: endUserLogger.error(msg);
0768: disableBackend(backend, true);
0769: backend = null;
0770: throw new SQLException(Translate.get(
0771: "loadbalancer.backend.unreacheable",
0772: backendName));
0773: }
0774:
0775: // Sanity check
0776: if (c == null)
0777: throw new SQLException(Translate.get(
0778: "loadbalancer.backend.no.connection",
0779: backend.getName()));
0780:
0781: // Execute Query
0782: ExecuteUpdateResult result;
0783: try {
0784: result = AbstractLoadBalancer
0785: .executeCallableStatementExecuteUpdateOnBackend(
0786: proc, backend, null, c);
0787: } catch (Exception e) {
0788: throw new SQLException(
0789: Translate
0790: .get(
0791: "loadbalancer.storedprocedure.failed.on.backend",
0792: new String[] {
0793: proc
0794: .getSqlShortForm(vdb
0795: .getSqlShortFormLength()),
0796: backend.getName(),
0797: e.getMessage() }));
0798: } finally {
0799: cm.releaseConnectionInAutoCommit(proc, c);
0800: }
0801: return result;
0802: } else { // Re-use the connection used by this transaction
0803: PooledConnection c = cm
0804: .retrieveConnectionForTransaction(proc
0805: .getTransactionId());
0806:
0807: // Sanity check
0808: if (c == null)
0809: throw new SQLException(Translate.get(
0810: "loadbalancer.unable.retrieve.connection",
0811: new String[] {
0812: String.valueOf(proc
0813: .getTransactionId()),
0814: backend.getName() }));
0815:
0816: // Execute Query
0817: try {
0818: ExecuteUpdateResult result = AbstractLoadBalancer
0819: .executeCallableStatementExecuteUpdateOnBackend(
0820: proc, backend, null, c);
0821: return result;
0822: } catch (Exception e) {
0823: throw new SQLException(
0824: Translate
0825: .get(
0826: "loadbalancer.storedprocedure.failed.on.backend",
0827: new String[] {
0828: proc
0829: .getSqlShortForm(vdb
0830: .getSqlShortFormLength()),
0831: backend.getName(),
0832: e.getMessage() }));
0833: }
0834: }
0835: } catch (RuntimeException e) {
0836: String msg = Translate.get(
0837: "loadbalancer.storedprocedure.failed.on.backend",
0838: new String[] {
0839: proc.getSqlShortForm(vdb
0840: .getSqlShortFormLength()),
0841: backend.getName(), e.getMessage() });
0842: logger.fatal(msg, e);
0843: endUserLogger.fatal(msg);
0844: throw new SQLException(msg);
0845: }
0846: }
0847:
0848: /**
0849: * @see org.continuent.sequoia.controller.loadbalancer.AbstractLoadBalancer#callableStatementExecute(StoredProcedure,
0850: * MetadataCache)
0851: */
0852: public ExecuteResult callableStatementExecute(StoredProcedure proc,
0853: MetadataCache metadataCache) throws SQLException {
0854: if (backend == null)
0855: throw new SQLException(
0856: "No available backend to execute stored procedure "
0857: + proc.getId());
0858:
0859: try {
0860: AbstractConnectionManager cm = backend
0861: .getConnectionManager(proc.getLogin());
0862: if (proc.isAutoCommit()) { // Use a connection just for this request
0863: PooledConnection c = null;
0864: try {
0865: c = cm.retrieveConnectionInAutoCommit(proc);
0866: } catch (UnreachableBackendException e1) {
0867: String backendName = backend.getName();
0868: String msg = Translate
0869: .get(
0870: "loadbalancer.backend.disabling.unreachable",
0871: backendName);
0872: logger.error(msg);
0873: endUserLogger.error(msg);
0874: disableBackend(backend, true);
0875: backend = null;
0876: throw new SQLException(Translate.get(
0877: "loadbalancer.backend.unreacheable",
0878: backendName));
0879: }
0880:
0881: // Sanity check
0882: if (c == null)
0883: throw new SQLException(Translate.get(
0884: "loadbalancer.backend.no.connection",
0885: backend.getName()));
0886:
0887: // Execute Query
0888: ExecuteResult rs = null;
0889: try {
0890: rs = AbstractLoadBalancer
0891: .executeCallableStatementExecuteOnBackend(
0892: proc, backend, null, c,
0893: metadataCache);
0894: } catch (Exception e) {
0895: throw new SQLException(
0896: Translate
0897: .get(
0898: "loadbalancer.storedprocedure.failed.on.backend",
0899: new String[] {
0900: proc
0901: .getSqlShortForm(vdb
0902: .getSqlShortFormLength()),
0903: backend.getName(),
0904: e.getMessage() }));
0905: } finally {
0906: cm.releaseConnectionInAutoCommit(proc, c);
0907: }
0908: return rs;
0909: } else { // Re-use the connection used by this transaction
0910: PooledConnection c = cm
0911: .retrieveConnectionForTransaction(proc
0912: .getTransactionId());
0913:
0914: // Sanity check
0915: if (c == null)
0916: throw new SQLException(Translate.get(
0917: "loadbalancer.unable.retrieve.connection",
0918: new String[] {
0919: String.valueOf(proc
0920: .getTransactionId()),
0921: backend.getName() }));
0922:
0923: // Execute Query
0924: try {
0925: ExecuteResult result = AbstractLoadBalancer
0926: .executeCallableStatementExecuteOnBackend(
0927: proc, backend, null, c,
0928: metadataCache);
0929: return result;
0930: } catch (Exception e) {
0931: throw new SQLException(
0932: Translate
0933: .get(
0934: "loadbalancer.storedprocedure.failed.on.backend",
0935: new String[] {
0936: proc
0937: .getSqlShortForm(vdb
0938: .getSqlShortFormLength()),
0939: backend.getName(),
0940: e.getMessage() }));
0941: }
0942: }
0943: } catch (RuntimeException e) {
0944: String msg = Translate.get(
0945: "loadbalancer.storedprocedure.failed.on.backend",
0946: new String[] {
0947: proc.getSqlShortForm(vdb
0948: .getSqlShortFormLength()),
0949: backend.getName(), e.getMessage() });
0950: logger.fatal(msg, e);
0951: endUserLogger.fatal(msg);
0952: throw new SQLException(msg);
0953: }
0954: }
0955:
0956: /**
0957: * @see org.continuent.sequoia.controller.loadbalancer.AbstractLoadBalancer#getPreparedStatementGetMetaData(AbstractRequest)
0958: */
0959: public ControllerResultSet getPreparedStatementGetMetaData(
0960: AbstractRequest request) throws SQLException {
0961: if (backend == null)
0962: throw new NoMoreBackendException(Translate.get(
0963: "loadbalancer.execute.no.backend.available",
0964: request.getSqlOrTemplate()));
0965:
0966: try {
0967: AbstractConnectionManager cm = backend
0968: .getConnectionManager(request.getLogin());
0969: ControllerResultSet rs = null;
0970: boolean badConnection;
0971: do {
0972: badConnection = false;
0973: // Use a connection just for this request
0974: PooledConnection c = null;
0975: try {
0976: c = cm.retrieveConnectionInAutoCommit(request);
0977: } catch (UnreachableBackendException e1) {
0978: String backendName = backend.getName();
0979: String msg = Translate
0980: .get(
0981: "loadbalancer.backend.disabling.unreachable",
0982: backendName);
0983: logger.error(msg);
0984: endUserLogger.error(msg);
0985: disableBackend(backend, true);
0986: backend = null;
0987: throw new SQLException(Translate.get(
0988: "loadbalancer.backend.unreacheable",
0989: backendName));
0990: }
0991:
0992: // Sanity check
0993: if (c == null)
0994: throw new SQLException(Translate.get(
0995: "loadbalancer.backend.no.connection",
0996: backend.getName()));
0997:
0998: // Execute Query
0999: try {
1000: rs = preparedStatementGetMetaDataOnBackend(request
1001: .getSqlOrTemplate(), backend, c
1002: .getConnection());
1003: cm.releaseConnectionInAutoCommit(request, c);
1004: } catch (SQLException e) {
1005: cm.releaseConnectionInAutoCommit(request, c);
1006: throw new SQLException(
1007: Translate
1008: .get(
1009: "loadbalancer.request.failed.on.backend",
1010: new String[] {
1011: request
1012: .getSqlOrTemplate(),
1013: backend.getName(),
1014: e.getMessage() }));
1015: } catch (BadConnectionException e) { // Get rid of the bad connection
1016: cm.deleteConnection(c);
1017: badConnection = true;
1018: } catch (Throwable e) {
1019: cm.releaseConnectionInAutoCommit(request, c);
1020: throw new SQLException(
1021: Translate
1022: .get(
1023: "loadbalancer.request.failed.on.backend",
1024: new String[] {
1025: request
1026: .getSqlOrTemplate(),
1027: backend.getName(),
1028: e.getMessage() }));
1029: }
1030: } while (badConnection);
1031: return rs;
1032: } catch (RuntimeException e) {
1033: String msg = Translate.get(
1034: "loadbalancer.getmetadata.failed", new String[] {
1035: request.getSqlOrTemplate(),
1036: backend.getURL(), e.getMessage() });
1037: logger.fatal(msg, e);
1038: endUserLogger.fatal(msg);
1039: throw new SQLException(msg);
1040: }
1041: }
1042:
1043: /*
1044: * Transaction management
1045: */
1046:
1047: /**
1048: * @see org.continuent.sequoia.controller.loadbalancer.AbstractLoadBalancer#abort(org.continuent.sequoia.controller.requestmanager.TransactionMetaData)
1049: */
1050: public void abort(TransactionMetaData tm) throws SQLException {
1051: rollback(tm);
1052: }
1053:
1054: /**
1055: * Begins a new transaction.
1056: *
1057: * @param tm the transaction marker metadata
1058: * @exception SQLException if an error occurs
1059: */
1060: public void begin(TransactionMetaData tm) throws SQLException {
1061: if (backend == null)
1062: throw new SQLException(
1063: "No available backend to begin transaction "
1064: + tm.getTransactionId());
1065:
1066: // We do not accept new transactions if we are disabling the backend
1067: if (!backend.canAcceptTasks(null))
1068: throw new SQLException(Translate.get(
1069: "loadbalancer.backend.is.disabling", new String[] {
1070: "begin transaction "
1071: + tm.getTransactionId(),
1072: backend.getName() }));
1073:
1074: try {
1075: PooledConnection c = backend.getConnectionManager(
1076: tm.getLogin()).getConnectionForTransaction(
1077: tm.getTransactionId());
1078:
1079: if (c == null)
1080: throw new SQLException(Translate.get(
1081: "loadbalancer.backend.no.connection", backend
1082: .getName()));
1083:
1084: c.getConnection().setAutoCommit(false);
1085: } catch (Exception e) {
1086: throw new SQLException("Begin of transaction "
1087: + tm.getTransactionId() + " failed on backend "
1088: + backend.getURL() + " (" + e + ")");
1089: }
1090: }
1091:
1092: /**
1093: * Commits a transaction.
1094: *
1095: * @param tm the transaction marker metadata
1096: * @exception SQLException if an error occurs
1097: */
1098: public void commit(TransactionMetaData tm) throws SQLException {
1099: if (backend == null)
1100: throw new SQLException(
1101: "No available backend to commit transaction "
1102: + tm.getTransactionId());
1103:
1104: try {
1105: AbstractConnectionManager cm = backend
1106: .getConnectionManager(tm.getLogin());
1107: PooledConnection pc = cm
1108: .retrieveConnectionForTransaction(tm
1109: .getTransactionId());
1110:
1111: if (pc == null)
1112: throw new SQLException(
1113: "No connection found for transaction "
1114: + tm.getTransactionId());
1115:
1116: try {
1117: Connection c = pc.getConnection();
1118: c.commit();
1119: c.setAutoCommit(true);
1120: } catch (SQLException e) {
1121: throw new SQLException(Translate.get(
1122: "loadbalancer.commit.failed", new String[] {
1123: String.valueOf(tm.getTransactionId()),
1124: backend.getName(), e.getMessage() }));
1125: } finally {
1126: cm.releaseConnectionForTransaction(tm
1127: .getTransactionId());
1128: }
1129: } catch (RuntimeException e) {
1130: String msg = Translate.get("loadbalancer.commit.failed",
1131: new String[] {
1132: String.valueOf(tm.getTransactionId()),
1133: backend.getName(), e.getMessage() });
1134: logger.fatal(msg, e);
1135: endUserLogger.fatal(msg);
1136: throw new SQLException(msg);
1137: }
1138: }
1139:
1140: /**
1141: * Rollbacks a transaction.
1142: *
1143: * @param tm the transaction marker metadata
1144: * @exception SQLException if an error occurs
1145: */
1146: public void rollback(TransactionMetaData tm) throws SQLException {
1147: if (backend == null)
1148: throw new SQLException(
1149: "No available backend to rollback transaction "
1150: + tm.getTransactionId());
1151:
1152: try {
1153: AbstractConnectionManager cm = backend
1154: .getConnectionManager(tm.getLogin());
1155: PooledConnection pc = cm
1156: .retrieveConnectionForTransaction(tm
1157: .getTransactionId());
1158:
1159: if (pc == null)
1160: throw new SQLException(
1161: "No connection found for transaction "
1162: + tm.getTransactionId());
1163:
1164: try {
1165: Connection c = pc.getConnection();
1166: c.rollback();
1167: c.setAutoCommit(true);
1168: } catch (SQLException e) {
1169: throw new SQLException(Translate.get(
1170: "loadbalancer.rollback.failed", new String[] {
1171: String.valueOf(tm.getTransactionId()),
1172: backend.getName(), e.getMessage() }));
1173: } finally {
1174: cm.releaseConnectionForTransaction(tm
1175: .getTransactionId());
1176: }
1177: } catch (RuntimeException e) {
1178: String msg = Translate.get("loadbalancer.rollback.failed",
1179: new String[] {
1180: String.valueOf(tm.getTransactionId()),
1181: backend.getName(), e.getMessage() });
1182: logger.fatal(msg, e);
1183: endUserLogger.fatal(msg);
1184: throw new SQLException(msg);
1185: }
1186: }
1187:
1188: /**
1189: * Rollback a transaction to a savepoint
1190: *
1191: * @param tm The transaction marker metadata
1192: * @param savepointName The name of the savepoint
1193: * @throws SQLException if an error occurs
1194: */
1195: public void rollbackToSavepoint(TransactionMetaData tm,
1196: String savepointName) throws SQLException {
1197: if (backend == null)
1198: throw new SQLException(
1199: "No available backend to rollback transaction "
1200: + tm.getTransactionId());
1201:
1202: try {
1203: AbstractConnectionManager cm = backend
1204: .getConnectionManager(tm.getLogin());
1205: PooledConnection c = cm.retrieveConnectionForTransaction(tm
1206: .getTransactionId());
1207:
1208: if (c == null)
1209: throw new SQLException(
1210: "No connection found for transaction "
1211: + tm.getTransactionId());
1212:
1213: Savepoint savepoint = backend.getSavepoint(new Long(tm
1214: .getTransactionId()), savepointName);
1215:
1216: if (savepoint == null)
1217: throw new SQLException("No savepoint with name "
1218: + savepointName
1219: + " has been found for transaction "
1220: + tm.getTransactionId());
1221:
1222: try {
1223: c.getConnection().rollback(savepoint);
1224: } catch (SQLException e) {
1225: throw new SQLException(Translate.get(
1226: "loadbalancer.rollbacksavepoint.failed",
1227: new String[] { savepointName,
1228: String.valueOf(tm.getTransactionId()),
1229: backend.getName(), e.getMessage() }));
1230: }
1231: } catch (RuntimeException e) {
1232: String msg = Translate.get(
1233: "loadbalancer.rollbacksavepoint.failed",
1234: new String[] { savepointName,
1235: String.valueOf(tm.getTransactionId()),
1236: backend.getName(), e.getMessage() });
1237: logger.fatal(msg, e);
1238: endUserLogger.fatal(msg);
1239: throw new SQLException(msg);
1240: }
1241: }
1242:
1243: /**
1244: * Release a savepoint from a transaction
1245: *
1246: * @param tm The transaction marker metadata
1247: * @param savepointName The name of the savepoint ro release
1248: * @throws SQLException if an error occurs
1249: */
1250: public void releaseSavepoint(TransactionMetaData tm,
1251: String savepointName) throws SQLException {
1252: if (backend == null)
1253: throw new SQLException(
1254: "No available backend to release savepoint from "
1255: + " transaction " + tm.getTransactionId());
1256:
1257: try {
1258: AbstractConnectionManager cm = backend
1259: .getConnectionManager(tm.getLogin());
1260: PooledConnection c = cm.retrieveConnectionForTransaction(tm
1261: .getTransactionId());
1262:
1263: if (c == null)
1264: throw new SQLException(
1265: "No connection found for transaction "
1266: + tm.getTransactionId());
1267:
1268: Savepoint savepoint = backend.getSavepoint(new Long(tm
1269: .getTransactionId()), savepointName);
1270:
1271: if (savepoint == null)
1272: throw new SQLException("No savepoint with name "
1273: + savepointName + " has been "
1274: + "found for transaction "
1275: + tm.getTransactionId());
1276:
1277: try {
1278: c.getConnection().releaseSavepoint(savepoint);
1279: } catch (SQLException e) {
1280: throw new SQLException(Translate.get(
1281: "loadbalancer.releasesavepoint.failed",
1282: new String[] { savepointName,
1283: String.valueOf(tm.getTransactionId()),
1284: backend.getName(), e.getMessage() }));
1285: } finally {
1286: backend.removeSavepoint(
1287: new Long(tm.getTransactionId()), savepoint);
1288: }
1289: } catch (RuntimeException e) {
1290: String msg = Translate.get(
1291: "loadbalancer.releasesavepoint.failed",
1292: new String[] { savepointName,
1293: String.valueOf(tm.getTransactionId()),
1294: backend.getName(), e.getMessage() });
1295: logger.fatal(msg, e);
1296: endUserLogger.fatal(msg);
1297: throw new SQLException(msg);
1298: }
1299: }
1300:
1301: /**
1302: * Set a savepoint to a transaction.
1303: *
1304: * @param tm The transaction marker metadata
1305: * @param savepointName The name of the new savepoint
1306: * @throws AllBackendsFailedException if no backend succeeded in setting the
1307: * savepoint.
1308: * @throws SQLException if an error occurs
1309: */
1310: public void setSavepoint(TransactionMetaData tm,
1311: String savepointName) throws AllBackendsFailedException,
1312: SQLException {
1313: if (backend == null)
1314: throw new SQLException(
1315: "No available backend to set savepoint to "
1316: + " transaction " + tm.getTransactionId());
1317:
1318: try {
1319: AbstractConnectionManager cm = backend
1320: .getConnectionManager(tm.getLogin());
1321: PooledConnection c = cm.retrieveConnectionForTransaction(tm
1322: .getTransactionId());
1323:
1324: if (c == null)
1325: throw new SQLException(
1326: "No connection found for transaction "
1327: + tm.getTransactionId());
1328:
1329: Savepoint savepoint = null;
1330: try {
1331: savepoint = c.getConnection().setSavepoint(
1332: savepointName);
1333: } catch (SQLException e) {
1334: throw new SQLException(Translate.get(
1335: "loadbalancer.setsavepoint.failed",
1336: new String[] { savepointName,
1337: String.valueOf(tm.getTransactionId()),
1338: backend.getName(), e.getMessage() }));
1339: } finally {
1340: if (savepoint != null)
1341: backend.addSavepoint(
1342: new Long(tm.getTransactionId()), savepoint);
1343: }
1344: } catch (RuntimeException e) {
1345: String msg = Translate.get(
1346: "loadbalancer.setsavepoint.failed", new String[] {
1347: savepointName,
1348: String.valueOf(tm.getTransactionId()),
1349: backend.getName(), e.getMessage() });
1350: logger.fatal(msg, e);
1351: endUserLogger.fatal(msg);
1352: throw new SQLException(msg);
1353: }
1354: }
1355:
1356: /**
1357: * @see org.continuent.sequoia.controller.loadbalancer.AbstractLoadBalancer#closePersistentConnection(java.lang.String,
1358: * long)
1359: */
1360: public void closePersistentConnection(String login,
1361: long persistentConnectionId) throws SQLException {
1362: AbstractConnectionManager cm = backend
1363: .getConnectionManager(login);
1364: if (cm != null) {
1365: // Release the connection if it exists
1366: cm
1367: .releasePersistentConnectionInAutoCommit(persistentConnectionId);
1368: backend.removePersistentConnection(persistentConnectionId);
1369: }
1370: }
1371:
1372: /**
1373: * @see org.continuent.sequoia.controller.loadbalancer.AbstractLoadBalancer#openPersistentConnection(String,
1374: * long)
1375: */
1376: public void openPersistentConnection(String login,
1377: long persistentConnectionId) throws SQLException {
1378: AbstractConnectionManager cm = backend
1379: .getConnectionManager(login);
1380: if (cm == null) {
1381: throw new SQLException(
1382: "No connection manager found for user " + login);
1383: }
1384:
1385: // Get a new connection
1386: AbstractRequest request = new UnknownReadRequest("", false, 0,
1387: "");
1388: request.setLogin(login);
1389: request.setPersistentConnection(true);
1390: request.setPersistentConnectionId(persistentConnectionId);
1391: try {
1392: PooledConnection c = cm
1393: .retrieveConnectionInAutoCommit(request);
1394: backend.addPersistentConnection(request
1395: .getPersistentConnectionId(), c);
1396: } catch (UnreachableBackendException e) {
1397: throw new SQLException(
1398: "Backend is not reachable to open persistent conenction "
1399: + persistentConnectionId);
1400: }
1401: }
1402:
1403: /*
1404: * Backends management
1405: */
1406:
1407: /**
1408: * Enables a backend that was previously disabled. Asks the corresponding
1409: * connection manager to initialize the connections if needed.
1410: *
1411: * @param db the database backend to enable
1412: * @param writeEnabled True if the backend must be enabled for writes
1413: * @throws SQLException if an error occurs
1414: */
1415: public void enableBackend(DatabaseBackend db, boolean writeEnabled)
1416: throws SQLException {
1417: if (backend != null) {
1418: if (backend.isReadEnabled())
1419: throw new SQLException(
1420: "SingleDB load balancer accepts only one backend and "
1421: + backend.getName()
1422: + " is already enabled. Skipping "
1423: + db.getName() + " initialization.");
1424: }
1425: backend = db;
1426: logger.info(Translate.get("loadbalancer.backend.enabling", db
1427: .getName()));
1428: if (!backend.isInitialized())
1429: backend.initializeConnections();
1430: backend.enableRead();
1431: if (writeEnabled)
1432: backend.enableWrite();
1433: }
1434:
1435: /**
1436: * Disables a backend that was previously enabled. Asks the corresponding
1437: * connection manager to finalize the connections if needed.
1438: *
1439: * @param db the database backend to disable
1440: * @param forceDisable true if disabling must be forced on the backend
1441: * @throws SQLException if an error occurs
1442: */
1443: public void disableBackend(DatabaseBackend db, boolean forceDisable)
1444: throws SQLException {
1445: if (backend.equals(db)) {
1446: logger.info(Translate.get("loadbalancer.backend.disabling",
1447: db.getName()));
1448: backend.disable();
1449: if (backend.isInitialized())
1450: backend.finalizeConnections();
1451: backend = null;
1452: } else {
1453: String msg = "Trying to disable a non-existing backend "
1454: + db.getName();
1455: logger.warn(msg);
1456: throw new SQLException(msg);
1457: }
1458: }
1459:
1460: /**
1461: * @see org.continuent.sequoia.controller.loadbalancer.AbstractLoadBalancer#setWeight(String,
1462: * int)
1463: */
1464: public void setWeight(String name, int w) throws SQLException {
1465: throw new SQLException(
1466: "Weight is not supported with this load balancer");
1467: }
1468:
1469: /**
1470: * @see org.continuent.sequoia.controller.loadbalancer.AbstractLoadBalancer#getNumberOfEnabledBackends()
1471: */
1472: public int getNumberOfEnabledBackends() {
1473: if (backend == null)
1474: return 0;
1475: else
1476: return 1;
1477: }
1478:
1479: /*
1480: * Debug/Monitoring
1481: */
1482:
1483: /**
1484: * Gets information about the request load balancer
1485: *
1486: * @return <code>String</code> containing information
1487: */
1488: public String getInformation() {
1489: if (backend == null)
1490: return "SingleDB Request load balancer: !!!Warning!!! No enabled backend node found\n";
1491: else
1492: return "SingleDB Request load balancer using "
1493: + backend.getURL() + "\n";
1494: }
1495:
1496: /**
1497: * @see org.continuent.sequoia.controller.loadbalancer.AbstractLoadBalancer#getXmlImpl()
1498: */
1499: public String getXmlImpl() {
1500: return "<" + DatabasesXmlTags.ELT_SingleDB + "/>";
1501: }
1502:
1503: }
|