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.common.sql.schema.DatabaseSchema;
032: import org.continuent.sequoia.controller.loadbalancer.AllBackendsFailedException;
033: import org.continuent.sequoia.controller.requestmanager.TransactionMetaData;
034: import org.continuent.sequoia.controller.requestmanager.distributed.DistributedRequestManager;
035: import org.continuent.sequoia.controller.requests.AbstractRequest;
036: import org.continuent.sequoia.controller.requests.UnknownWriteRequest;
037:
038: /**
039: * Execute a distributed set savepoint
040: *
041: * @author <a href="mailto:jbvanzuylen@transwide.com">Jean-Bernard van Zuylen
042: * </a>
043: * @author <a href="mailto:emmanuel.cecchet@continuent.com">Emmanuel Cecchet
044: * </a>
045: * @version 1.0
046: */
047: public class DistributedSetSavepoint extends
048: DistributedTransactionMarker {
049: private static final long serialVersionUID = 1429582815473734482L;
050:
051: // Login that sets the savepoint. This is used in case the remote
052: // controller has to lazily start the transaction.
053: private String login;
054:
055: private String savepointName;
056:
057: /**
058: * Creates a new <code>SetSavepoint</code> message.
059: *
060: * @param login login that sets the savepoint
061: * @param transactionId id of the transaction
062: * @param savepointName the savepoint name
063: */
064: public DistributedSetSavepoint(String login, long transactionId,
065: String savepointName) {
066: super (transactionId);
067: this .login = login;
068: this .savepointName = savepointName;
069: }
070:
071: /**
072: * @see org.continuent.sequoia.controller.virtualdatabase.protocol.DistributedTransactionMarker#scheduleCommand(DistributedRequestManager)
073: */
074: public Object scheduleCommand(DistributedRequestManager drm)
075: throws SQLException {
076: LinkedList totalOrderQueue = drm.getVirtualDatabase()
077: .getTotalOrderQueue();
078: if (totalOrderQueue != null) {
079: synchronized (totalOrderQueue) {
080: totalOrderQueue.addLast(this );
081: }
082: }
083: return this ;
084: }
085:
086: /**
087: * @see org.continuent.sequoia.controller.virtualdatabase.protocol.DistributedTransactionMarker#executeCommand(DistributedRequestManager)
088: */
089: public Serializable executeCommand(DistributedRequestManager drm)
090: throws SQLException {
091: boolean hasBeenScheduled = false;
092:
093: // Let's find the transaction marker since it will be used even for
094: // logging purposes
095: Long tid = new Long(transactionId);
096: TransactionMetaData tm;
097: try {
098: tm = drm.getTransactionMetaData(tid);
099: } catch (SQLException e) {
100: // Lazily start the transaction using a fake request
101: FakeRequest fr = new FakeRequest();
102: fr.setIsAutoCommit(false);
103: fr.setTransactionId(transactionId);
104: fr.setLogin(login);
105: drm.lazyTransactionStart(fr);
106: tm = drm.getTransactionMetaData(tid);
107: }
108:
109: try {
110: // Wait for the scheduler to give us the authorization to execute
111: drm.getScheduler().setSavepoint(tm, savepointName, this );
112: hasBeenScheduled = true;
113:
114: if (drm.getLogger().isDebugEnabled())
115: drm
116: .getLogger()
117: .debug(
118: Translate
119: .get(
120: "transaction.setsavepoint",
121: new String[] {
122: savepointName,
123: String
124: .valueOf(transactionId) }));
125:
126: // Send to load balancer
127: drm.getLoadBalancer().setSavepoint(tm, savepointName);
128:
129: // Update recovery log
130: drm.getRecoveryLog().logRequestCompletion(tm.getLogId(),
131: true, 0);
132:
133: // Notify scheduler for completion
134: drm.getScheduler().savepointCompleted(transactionId);
135: } catch (NoMoreBackendException e) {
136: if (drm.getLogger().isDebugEnabled())
137: drm
138: .getLogger()
139: .debug(
140: Translate
141: .get(
142: "virtualdatabase.distributed.setsavepoint.logging.only",
143: new String[] {
144: savepointName,
145: String
146: .valueOf(transactionId) }));
147:
148: addSavepointFailureOnAllBackends(drm, hasBeenScheduled, tm);
149: throw e;
150: } catch (SQLException e) {
151: addSavepointFailureOnAllBackends(drm, hasBeenScheduled, tm);
152: drm
153: .getLogger()
154: .warn(
155: Translate
156: .get("virtualdatabase.distributed.setsavepoint.sqlexception"),
157: e);
158: return e;
159: } catch (RuntimeException re) {
160: addSavepointFailureOnAllBackends(drm, hasBeenScheduled, tm);
161: drm
162: .getLogger()
163: .warn(
164: Translate
165: .get("virtualdatabase.distributed.setsavepoint.exception"),
166: re);
167: throw new SQLException(re.getMessage());
168: } catch (AllBackendsFailedException e) {
169: addSavepointFailureOnAllBackends(drm, hasBeenScheduled, tm);
170: if (drm.getLogger().isDebugEnabled())
171: drm
172: .getLogger()
173: .debug(
174: Translate
175: .get(
176: "virtualdatabase.distributed.setsavepoint.all.backends.locally.failed",
177: new String[] {
178: savepointName,
179: String
180: .valueOf(transactionId) }));
181: return e;
182: }
183:
184: // Add savepoint name to list of savepoints for this transaction
185: drm.addSavepoint(tid, savepointName);
186: return Boolean.TRUE;
187: }
188:
189: private void addSavepointFailureOnAllBackends(
190: DistributedRequestManager drm, boolean hasBeenScheduled,
191: TransactionMetaData tm) {
192: AbstractRequest request = new UnknownWriteRequest("savepoint "
193: + savepointName, false, 0, "\n");
194: request.setTransactionId(transactionId);
195: request.setLogId(tm.getLogId());
196: drm.addFailedOnAllBackends(request, hasBeenScheduled);
197: }
198:
199: /**
200: * Returns the savepointName value.
201: *
202: * @return Returns the savepointName.
203: */
204: public String getSavepointName() {
205: return savepointName;
206: }
207:
208: /**
209: * @see java.lang.Object#equals(java.lang.Object)
210: */
211: public boolean equals(Object obj) {
212: if (super .equals(obj))
213: return savepointName.equals(((DistributedSetSavepoint) obj)
214: .getSavepointName());
215: else
216: return false;
217: }
218:
219: /**
220: * @see java.lang.Object#toString()
221: */
222: public String toString() {
223: return "Set savepoint " + savepointName + " to transaction "
224: + transactionId;
225: }
226:
227: // This is used in case the remote
228: // controller has to lazily start the transaction.
229: private class FakeRequest extends AbstractRequest {
230: private static final long serialVersionUID = 5694250075466219713L;
231:
232: /**
233: * Creates a new <code>FakeRequest</code> object with a null SQL
234: * statement.
235: */
236: public FakeRequest() {
237: super (null, false, 0, null, 0);
238: }
239:
240: /**
241: * @see org.continuent.sequoia.controller.requests.AbstractRequest#altersAggregateList()
242: */
243: public boolean altersAggregateList() {
244: return false;
245: }
246:
247: /**
248: * @see org.continuent.sequoia.controller.requests.AbstractRequest#altersDatabaseCatalog()
249: */
250: public boolean altersDatabaseCatalog() {
251: return false;
252: }
253:
254: /**
255: * @see org.continuent.sequoia.controller.requests.AbstractRequest#altersDatabaseSchema()
256: */
257: public boolean altersDatabaseSchema() {
258: return false;
259: }
260:
261: /**
262: * @see org.continuent.sequoia.controller.requests.AbstractRequest#altersMetadataCache()
263: */
264: public boolean altersMetadataCache() {
265: return false;
266: }
267:
268: /**
269: * @see org.continuent.sequoia.controller.requests.AbstractRequest#altersQueryResultCache()
270: */
271: public boolean altersQueryResultCache() {
272: return false;
273: }
274:
275: /**
276: * @see org.continuent.sequoia.controller.requests.AbstractRequest#altersStoredProcedureList()
277: */
278: public boolean altersStoredProcedureList() {
279: return false;
280: }
281:
282: /**
283: * @see org.continuent.sequoia.controller.requests.AbstractRequest#altersUserDefinedTypes()
284: */
285: public boolean altersUserDefinedTypes() {
286: return false;
287: }
288:
289: /**
290: * @see org.continuent.sequoia.controller.requests.AbstractRequest#altersUsers()
291: */
292: public boolean altersUsers() {
293: return false;
294: }
295:
296: /**
297: * @see org.continuent.sequoia.controller.requests.AbstractRequest#altersSomething()
298: */
299: public boolean altersSomething() {
300: return false;
301: }
302:
303: /**
304: * @see org.continuent.sequoia.controller.requests.AbstractRequest#cloneParsing(org.continuent.sequoia.controller.requests.AbstractRequest)
305: */
306: public void cloneParsing(AbstractRequest request) {
307: }
308:
309: /**
310: * @see org.continuent.sequoia.controller.requests.AbstractRequest#needsMacroProcessing()
311: */
312: public boolean needsMacroProcessing() {
313: return false;
314: }
315:
316: /**
317: * @see org.continuent.sequoia.controller.requests.AbstractRequest#parse(org.continuent.sequoia.common.sql.schema.DatabaseSchema,
318: * int, boolean)
319: */
320: public void parse(DatabaseSchema schema, int granularity,
321: boolean isCaseSensitive) throws SQLException {
322: }
323:
324: }
325:
326: }
|