001: /**
002: * Sequoia: Database clustering technology.
003: * Copyright (C) 2005 AmicoSoft, Inc. dba Emic Networks
004: * Copyright (C) 2005-2006 Continuent, Inc.
005: * Contact: sequoia@continuent.org
006: *
007: * Licensed under the Apache License, Version 2.0 (the "License");
008: * you may not use this file except in compliance with the License.
009: * You may obtain a copy of the License at
010: *
011: * http://www.apache.org/licenses/LICENSE-2.0
012: *
013: * Unless required by applicable law or agreed to in writing, software
014: * distributed under the License is distributed on an "AS IS" BASIS,
015: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016: * See the License for the specific language governing permissions and
017: * limitations under the License.
018: *
019: * Initial developer(s): Emmanuel Cecchet.
020: * Contributor(s): ______________________.
021: */package org.continuent.sequoia.controller.virtualdatabase.protocol;
022:
023: import java.io.Serializable;
024: import java.sql.SQLException;
025: import java.util.LinkedList;
026:
027: import org.continuent.sequoia.common.exceptions.NoMoreBackendException;
028: import org.continuent.sequoia.common.i18n.Translate;
029: import org.continuent.sequoia.controller.requestmanager.distributed.DistributedRequestManager;
030: import org.continuent.sequoia.controller.requests.SelectRequest;
031:
032: /**
033: * Execute a distributed read request such as SELECT FOR ... UPDATE.
034: *
035: * @author <a href="mailto:emmanuel.cecchet@continuent.com">Emmanuel Cecchet
036: * </a>
037: * @version 1.0
038: */
039: public class DistributedStatementExecuteQuery extends
040: DistributedRequest {
041: private static final long serialVersionUID = -7183844510032678987L;
042:
043: /**
044: * Creates a new <code>ExecRemoteStatementExecuteQuery</code> object.
045: *
046: * @param request select request to execute
047: */
048: public DistributedStatementExecuteQuery(SelectRequest request) {
049: super (request);
050: }
051:
052: /**
053: * @see org.continuent.sequoia.controller.virtualdatabase.protocol.DistributedRequest#scheduleRequest(org.continuent.sequoia.controller.requestmanager.distributed.DistributedRequestManager)
054: */
055: public Object scheduleRequest(DistributedRequestManager drm)
056: throws SQLException {
057: if (((SelectRequest) request).isMustBroadcast()) { // Total order queue is only needed for broadcasted select statements
058: LinkedList totalOrderQueue = drm.getVirtualDatabase()
059: .getTotalOrderQueue();
060: synchronized (totalOrderQueue) {
061: totalOrderQueue.addLast(request);
062: }
063: }
064: return request;
065: }
066:
067: /**
068: * @see org.continuent.sequoia.controller.virtualdatabase.protocol.DistributedRequest#executeScheduledRequest(org.continuent.sequoia.controller.requestmanager.distributed.DistributedRequestManager)
069: */
070: public Serializable executeScheduledRequest(
071: DistributedRequestManager drm) throws SQLException {
072: Serializable result = null;
073: SelectRequest selectRequest = ((SelectRequest) request);
074: try {
075: if (selectRequest.isMustBroadcast()
076: || (!selectRequest.isAutoCommit())) {
077: drm.getLoadBalancer().waitForSuspendWritesToComplete(
078: request);
079: // Lazily start the transaction and log begin since this request will be
080: // logged as well. Else let the transaction be started lazily by the
081: // load balancer without logging the transaction begin in the recovery
082: // log.
083: drm.lazyTransactionStart(request);
084: }
085:
086: result = drm.execLocalStatementExecuteQuery(selectRequest);
087:
088: if (drm.storeRequestResult(request, result))
089: result = DistributedRequestManager.SUCCESSFUL_COMPLETION;
090:
091: return result;
092: } catch (NoMoreBackendException e) {
093: if (drm.getLogger().isDebugEnabled())
094: drm
095: .getLogger()
096: .debug(
097: Translate
098: .get(
099: "virtualdatabase.distributed.write.logging.only",
100: request
101: .getSqlShortForm(drm
102: .getVirtualDatabase()
103: .getSqlShortFormLength())));
104:
105: /**
106: * Add the failed request to the failedOnAllBackends list for later
107: * notification (@see
108: * DistributedRequestManager#completeFailedOnAllBackends(AbstractRequest,
109: * boolean)). The request will be logged later if it was successful on
110: * other controllers.
111: * <p>
112: * The code in drm.execLocalStatementExecuteQuery always notify the
113: * scheduler (even in the presence of failures), so there is no need for
114: * further scheduler notification (this explains the false in
115: * drm.addFailedOnAllBackends(request, false)).
116: */
117: drm.addFailedOnAllBackends(request, false);
118:
119: return e;
120: } catch (SQLException e) {
121: /**
122: * Add the failed request to the failedOnAllBackends list for later
123: * notification (@see
124: * DistributedRequestManager#completeFailedOnAllBackends(AbstractRequest,
125: * boolean)). The request will be logged later if it was successful on
126: * other controllers.
127: * <p>
128: * The code in drm.execLocalStatementExecuteQuery always notify the
129: * scheduler (even in the presence of failures), so there is no need for
130: * further scheduler notification (this explains the false in
131: * drm.addFailedOnAllBackends(request, false)).
132: */
133: drm.addFailedOnAllBackends(request, false);
134: drm
135: .getLogger()
136: .warn(
137: Translate
138: .get(
139: "virtualdatabase.distributed.read.sqlexception",
140: e.getMessage()), e);
141: if (selectRequest.isMustBroadcast()) {
142: // Be sure to remove the query from the total order queue if failure
143: // occured before removal from the queue
144: drm.getLoadBalancer()
145: .removeObjectFromAndNotifyTotalOrderQueue(
146: request);
147: }
148: return e;
149: } catch (RuntimeException re) {
150: /**
151: * Add the failed request to the failedOnAllBackends list for later
152: * notification (@see
153: * DistributedRequestManager#completeFailedOnAllBackends(AbstractRequest,
154: * boolean)). The request will be logged later if it was successful on
155: * other controllers.
156: * <p>
157: * The code in drm.execLocalStatementExecuteQuery always notify the
158: * scheduler (even in the presence of failures), so there is no need for
159: * further scheduler notification (this explains the false in
160: * drm.addFailedOnAllBackends(request, false)).
161: */
162: drm.addFailedOnAllBackends(request, false);
163: drm
164: .getLogger()
165: .warn(
166: Translate
167: .get(
168: "virtualdatabase.distributed.read.exception",
169: re.getMessage()), re);
170: if (selectRequest.isMustBroadcast()) {
171: // Be sure to remove the query from the total order queue if failure
172: // occured before removal from the queue
173: drm.getLoadBalancer()
174: .removeObjectFromAndNotifyTotalOrderQueue(
175: request);
176: }
177: return new SQLException(re.getMessage());
178: }
179: }
180:
181: /**
182: * @see java.lang.Object#toString()
183: */
184: public String toString() {
185: return "S " + request.getId() + " "
186: + request.getTransactionId() + " "
187: + request.getUniqueKey();
188: }
189:
190: }
|