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: * Copyright (C) 2005-2006 Continuent, Inc.
007: * Contact: sequoia@continuent.org
008: *
009: * Licensed under the Apache License, Version 2.0 (the "License");
010: * you may not use this file except in compliance with the License.
011: * You may obtain a copy of the License at
012: *
013: * http://www.apache.org/licenses/LICENSE-2.0
014: *
015: * Unless required by applicable law or agreed to in writing, software
016: * distributed under the License is distributed on an "AS IS" BASIS,
017: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
018: * See the License for the specific language governing permissions and
019: * limitations under the License.
020: *
021: * Initial developer(s): Jean-Bernard van Zuylen.
022: * Contributor(s): Emmanuel Cecchet.
023: */package org.continuent.sequoia.controller.virtualdatabase.protocol;
024:
025: import java.io.Serializable;
026: import java.sql.SQLException;
027: import java.util.LinkedList;
028:
029: import org.continuent.sequoia.common.exceptions.NoMoreBackendException;
030: import org.continuent.sequoia.common.i18n.Translate;
031: import org.continuent.sequoia.controller.loadbalancer.AllBackendsFailedException;
032: import org.continuent.sequoia.controller.requestmanager.TransactionMetaData;
033: import org.continuent.sequoia.controller.requestmanager.distributed.DistributedRequestManager;
034: import org.continuent.sequoia.controller.requests.AbstractRequest;
035: import org.continuent.sequoia.controller.requests.UnknownWriteRequest;
036:
037: /**
038: * Execute a distributed release savepoint
039: *
040: * @author <a href="mailto:jbvanzuylen@transwide.com">Jean-Bernard van Zuylen
041: * </a>
042: * @author <a href="mailto:emmanuel.cecchet@continuent.com">Emmanuel Cecchet
043: * </a>
044: * @version 1.0
045: */
046: public class DistributedReleaseSavepoint extends
047: DistributedTransactionMarker {
048: private static final long serialVersionUID = 3025352266902951038L;
049:
050: private String savepointName;
051:
052: /**
053: * Creates a new <code>ReleaseSavepoint</code> message
054: *
055: * @param transactionId the transaction identifier
056: * @param savepointName the savepoint name
057: */
058: public DistributedReleaseSavepoint(long transactionId,
059: String savepointName) {
060: super (transactionId);
061: this .savepointName = savepointName;
062: }
063:
064: /**
065: * @see org.continuent.sequoia.controller.virtualdatabase.protocol.DistributedTransactionMarker#scheduleCommand(org.continuent.sequoia.controller.requestmanager.distributed.DistributedRequestManager)
066: */
067: public Object scheduleCommand(DistributedRequestManager drm)
068: throws SQLException {
069: LinkedList totalOrderQueue = drm.getVirtualDatabase()
070: .getTotalOrderQueue();
071: if (totalOrderQueue != null) {
072: synchronized (totalOrderQueue) {
073: totalOrderQueue.addLast(this );
074: }
075: }
076: return this ;
077: }
078:
079: /**
080: * @see org.continuent.sequoia.controller.virtualdatabase.protocol.DistributedTransactionMarker#executeCommand(org.continuent.sequoia.controller.requestmanager.distributed.DistributedRequestManager)
081: */
082: public Serializable executeCommand(DistributedRequestManager drm)
083: throws SQLException {
084: boolean hasBeenScheduled = false;
085:
086: // Let's find the transaction marker since it will be used even for
087: // logging purposes
088: Long tid = new Long(transactionId);
089: TransactionMetaData tm;
090: try {
091: tm = drm.getTransactionMetaData(tid);
092: } catch (SQLException e) {
093: // Remove the rollback from the total order queue
094: drm.getLoadBalancer()
095: .removeObjectFromAndNotifyTotalOrderQueue(this );
096: throw e;
097: }
098:
099: // Check that a savepoint with given name has been set
100: if (!drm.hasSavepoint(tid, savepointName))
101: throw new SQLException(Translate.get(
102: "transaction.savepoint.not.found", new String[] {
103: savepointName,
104: String.valueOf(transactionId) }));
105:
106: try {
107: // Wait for the scheduler to give us the authorization to execute
108: drm.getScheduler()
109: .releaseSavepoint(tm, savepointName, this );
110: hasBeenScheduled = true;
111:
112: if (drm.getLogger().isDebugEnabled())
113: drm
114: .getLogger()
115: .debug(
116: Translate
117: .get(
118: "transaction.releasesavepoint",
119: new String[] {
120: savepointName,
121: String
122: .valueOf(transactionId) }));
123:
124: // Send to load balancer
125: drm.getLoadBalancer().releaseSavepoint(tm, savepointName);
126:
127: // Update recovery log
128: drm.getRecoveryLog().logRequestCompletion(tm.getLogId(),
129: true, 0);
130:
131: // Notify scheduler for completion
132: drm.getScheduler().savepointCompleted(transactionId);
133: } catch (NoMoreBackendException e) {
134: addFailureOnAllBackends(drm, hasBeenScheduled, tm);
135: if (drm.getLogger().isDebugEnabled())
136: drm
137: .getLogger()
138: .debug(
139: Translate
140: .get(
141: "virtualdatabase.distributed.releasesavepoint.logging.only",
142: new String[] {
143: savepointName,
144: String
145: .valueOf(transactionId) }));
146: throw e;
147: } catch (SQLException e) {
148: addFailureOnAllBackends(drm, hasBeenScheduled, tm);
149: drm
150: .getLogger()
151: .warn(
152: Translate
153: .get("virtualdatabase.distributed.releasesavepoint.sqlexception"),
154: e);
155: return e;
156: } catch (RuntimeException re) {
157: addFailureOnAllBackends(drm, hasBeenScheduled, tm);
158: drm
159: .getLogger()
160: .warn(
161: Translate
162: .get("virtualdatabase.distributed.releasesavepoint.exception"),
163: re);
164: throw new SQLException(re.getMessage());
165: } catch (AllBackendsFailedException e) {
166: addFailureOnAllBackends(drm, hasBeenScheduled, tm);
167: if (drm.getLogger().isDebugEnabled())
168: drm
169: .getLogger()
170: .debug(
171: Translate
172: .get(
173: "virtualdatabase.distributed.releasesavepoint.all.backends.locally.failed",
174: new String[] {
175: savepointName,
176: String
177: .valueOf(transactionId) }));
178: return e;
179: } finally {
180: // Remove savepoint for the transaction
181: drm.removeSavepoint(tid, savepointName);
182: }
183: return Boolean.TRUE;
184: }
185:
186: private void addFailureOnAllBackends(DistributedRequestManager drm,
187: boolean hasBeenScheduled, TransactionMetaData tm) {
188: AbstractRequest request = new UnknownWriteRequest("release "
189: + savepointName, false, 0, "\n");
190: request.setTransactionId(transactionId);
191: request.setLogId(tm.getLogId());
192: drm.addFailedOnAllBackends(request, hasBeenScheduled);
193: }
194:
195: /**
196: * Returns the savepointName value.
197: *
198: * @return Returns the savepointName.
199: */
200: public String getSavepointName() {
201: return savepointName;
202: }
203:
204: /**
205: * @see java.lang.Object#equals(java.lang.Object)
206: */
207: public boolean equals(Object obj) {
208: if (super .equals(obj))
209: return savepointName
210: .equals(((DistributedReleaseSavepoint) obj)
211: .getSavepointName());
212: else
213: return false;
214: }
215:
216: /**
217: * @see java.lang.Object#toString()
218: */
219: public String toString() {
220: return "Release savepoint " + savepointName
221: + " from transaction " + transactionId;
222: }
223: }
|