001: /**
002: * Sequoia: Database clustering technology.
003: * Copyright (C) 2002-2004 French National Institute For Research In Computer
004: * Science And Control (INRIA).
005: * Copyright (C) 2005 AmicoSoft, Inc. dba Emic Networks
006: * Contact: sequoia@continuent.org
007: *
008: * Licensed under the Apache License, Version 2.0 (the "License");
009: * you may not use this file except in compliance with the License.
010: * You may obtain a copy of the License at
011: *
012: * http://www.apache.org/licenses/LICENSE-2.0
013: *
014: * Unless required by applicable law or agreed to in writing, software
015: * distributed under the License is distributed on an "AS IS" BASIS,
016: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: * See the License for the specific language governing permissions and
018: * limitations under the License.
019: *
020: * Initial developer(s): Jean-Bernard van Zuylen.
021: * Contributor(s): ______________________.
022: */package org.continuent.sequoia.controller.loadbalancer.tasks;
023:
024: import java.sql.SQLException;
025: import java.sql.Savepoint;
026:
027: import org.continuent.sequoia.common.i18n.Translate;
028: import org.continuent.sequoia.common.log.Trace;
029: import org.continuent.sequoia.controller.backend.DatabaseBackend;
030: import org.continuent.sequoia.controller.connection.AbstractConnectionManager;
031: import org.continuent.sequoia.controller.connection.PooledConnection;
032: import org.continuent.sequoia.controller.loadbalancer.BackendWorkerThread;
033: import org.continuent.sequoia.controller.requestmanager.TransactionMetaData;
034: import org.continuent.sequoia.controller.requests.AbstractRequest;
035:
036: /**
037: * Task to remove a savepoint from a transaction.
038: *
039: * @author <a href="mailto:jbvanzuylen@transwide.com">Jean-Bernard van Zuylen
040: * </a>
041: * @version 1.0
042: */
043: public class ReleaseSavepointTask extends AbstractTask {
044: /** Transaction metadata (login, transaction id, timeout) */
045: private TransactionMetaData tm;
046: /** Name of the savepoint. */
047: private String savepointName;
048:
049: static Trace endUserLogger = Trace
050: .getLogger("org.continuent.sequoia.enduser");
051:
052: /**
053: * Creates a new <code>ReleaseSavepointTask</code> object
054: *
055: * @param nbToComplete number of threads that must succeed before returning
056: * @param totalNb total number of threads
057: * @param tm transaction metadata
058: * @param savepointName the savepoint to remove
059: * @throws NullPointerException if tm is null
060: */
061: public ReleaseSavepointTask(int nbToComplete, int totalNb,
062: TransactionMetaData tm, String savepointName)
063: throws NullPointerException {
064: super (nbToComplete, totalNb, tm.isPersistentConnection(), tm
065: .getPersistentConnectionId());
066: if (tm == null)
067: throw new NullPointerException(
068: "Unexpected null metadata in BeginTask");
069: this .tm = tm;
070: this .savepointName = savepointName;
071: }
072:
073: /**
074: * @see org.continuent.sequoia.controller.loadbalancer.tasks.AbstractTask#executeTask(org.continuent.sequoia.controller.loadbalancer.BackendWorkerThread)
075: */
076: public void executeTask(BackendWorkerThread backendThread)
077: throws SQLException {
078: DatabaseBackend backend = backendThread.getBackend();
079: Long lTid = new Long(tm.getTransactionId());
080:
081: AbstractConnectionManager cm = backend.getConnectionManager(tm
082: .getLogin());
083: if (cm == null) {
084: SQLException se = new SQLException(
085: "No Connection Manager for Virtual Login:"
086: + tm.getLogin());
087: try {
088: notifyFailure(backendThread, -1, se);
089: } catch (SQLException ignore) {
090:
091: }
092: throw se;
093: }
094: PooledConnection c = cm.retrieveConnectionForTransaction(tm
095: .getTransactionId());
096:
097: // Sanity check
098: if (c == null) { // Bad connection
099: backend.stopTransaction(lTid);
100: SQLException se = new SQLException(
101: "Unable to retrieve connection for transaction "
102: + tm.getTransactionId());
103:
104: try { // All backends failed, just ignore
105: if (!notifyFailure(backendThread, tm.getTimeout(), se))
106: return;
107: } catch (SQLException ignore) {
108: }
109: // Disable this backend (it is no more in sync) by killing the backend
110: // thread
111: backendThread.getLoadBalancer().disableBackend(backend,
112: true);
113: String msg = "Failed to release savepoint for transaction "
114: + tm.getTransactionId() + " on backend "
115: + backend.getName() + " but " + getSuccess()
116: + " succeeded (" + se + ")";
117: backendThread.getLogger().error(msg);
118: endUserLogger.error(Translate
119: .get("loadbalancer.backend.disabling", backend
120: .getName()));
121: throw new SQLException(msg);
122: }
123:
124: // Execute Query
125: Savepoint savepoint = null;
126: try {
127: savepoint = backend.getSavepoint(lTid, savepointName);
128: c.getConnection().releaseSavepoint(savepoint);
129: } catch (Exception e) {
130: try {
131: if (!notifyFailure(backendThread, tm.getTimeout(),
132: new SQLException(e.getMessage())))
133: return;
134: } catch (SQLException ignore) {
135: }
136: // Disable this backend (it is no more in sync) by killing the backend
137: // thread
138: backendThread.getLoadBalancer().disableBackend(backend,
139: true);
140: String msg = "Failed to release savepoint for transaction "
141: + tm.getTransactionId() + " on backend "
142: + backend.getName() + " but " + getSuccess()
143: + " succeeded (" + e + ")";
144: backendThread.getLogger().error(msg);
145: endUserLogger.error(Translate
146: .get("loadbalancer.backend.disabling", backend
147: .getName()));
148: throw new SQLException(msg);
149: } finally {
150: backend.removeSavepoint(lTid, savepoint);
151: }
152:
153: notifySuccess(backendThread);
154: }
155:
156: /**
157: * @see org.continuent.sequoia.controller.loadbalancer.tasks.AbstractTask#getRequest()
158: */
159: public AbstractRequest getRequest() {
160: return null;
161: }
162:
163: /**
164: * @return savepoint name
165: */
166: public String getSavepointName() {
167: return savepointName;
168: }
169:
170: /**
171: * @see org.continuent.sequoia.controller.loadbalancer.tasks.AbstractTask#getTransactionId()
172: */
173: public long getTransactionId() {
174: return tm.getTransactionId();
175: }
176:
177: /**
178: * @see org.continuent.sequoia.controller.loadbalancer.tasks.AbstractTask#isAutoCommit()
179: */
180: public boolean isAutoCommit() {
181: return false;
182: }
183:
184: /**
185: * @see java.lang.Object#equals(java.lang.Object)
186: */
187: public boolean equals(Object other) {
188: if ((other == null) || !(other instanceof ReleaseSavepointTask))
189: return false;
190:
191: ReleaseSavepointTask releaseSavepoint = (ReleaseSavepointTask) other;
192: return (this .getTransactionId() == releaseSavepoint
193: .getTransactionId())
194: && (this .savepointName.equals(releaseSavepoint
195: .getSavepointName()));
196: }
197:
198: /**
199: * @see java.lang.Object#hashCode()
200: */
201: public int hashCode() {
202: return (int) this .getTransactionId();
203: }
204:
205: /**
206: * @see java.lang.Object#toString()
207: */
208: public String toString() {
209: return "ReleaseSavepointTask for transaction "
210: + tm.getTransactionId() + " (" + savepointName + ")";
211: }
212: }
|