001: /**
002: * Sequoia: Database clustering technology.
003: * Copyright (C) 2002-2004 French National Institute For Research In Computer
004: * Science And Control (INRIA).
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.loadbalancer.paralleldb;
022:
023: import java.sql.SQLException;
024: import java.util.ArrayList;
025:
026: import org.continuent.sequoia.common.exceptions.NoMoreBackendException;
027: import org.continuent.sequoia.common.i18n.Translate;
028: import org.continuent.sequoia.common.xml.DatabasesXmlTags;
029: import org.continuent.sequoia.controller.backend.DatabaseBackend;
030: import org.continuent.sequoia.controller.requests.AbstractRequest;
031: import org.continuent.sequoia.controller.requests.AbstractWriteRequest;
032: import org.continuent.sequoia.controller.virtualdatabase.VirtualDatabase;
033:
034: /**
035: * This class defines a ParallelDB_RR load balancer. This load balancer performs
036: * simple round-robin for read and write queries execution.
037: *
038: * @author <a href="mailto:Emmanuel.Cecchet@inria.fr">Emmanuel Cecchet </a>
039: * @version 1.0
040: */
041: public class ParallelDB_RR extends ParallelDB {
042:
043: private int index = 0;
044:
045: /**
046: * Creates a new <code>ParallelDB_RR</code> object
047: *
048: * @param vdb the virtual database this load balancer belongs to.
049: * @throws Exception if an error occurs
050: */
051: public ParallelDB_RR(VirtualDatabase vdb) throws Exception {
052: super (vdb);
053: }
054:
055: /**
056: * Choose a backend using a round-robin algorithm for read request execution.
057: *
058: * @param request request to execute
059: * @return the chosen backend
060: * @throws SQLException if an error occurs
061: */
062: public DatabaseBackend chooseBackendForReadRequest(
063: AbstractRequest request) throws SQLException {
064: // Choose a backend
065: try {
066: vdb.acquireReadLockBackendLists();
067: } catch (InterruptedException e) {
068: String msg = Translate.get(
069: "loadbalancer.backendlist.acquire.readlock.failed",
070: e);
071: logger.error(msg);
072: throw new SQLException(msg);
073: }
074:
075: DatabaseBackend backend = null; // The backend that will execute the query
076:
077: // Note that vdb lock is released in the finally clause of this try/catch
078: // block
079: try {
080: ArrayList backends = vdb.getBackends();
081: int size = backends.size();
082:
083: if (size == 0)
084: throw new NoMoreBackendException(Translate.get(
085: "loadbalancer.execute.no.backend.available",
086: request.getId()));
087:
088: // Take the next backend
089: int maxTries = size;
090: synchronized (this ) {
091: do {
092: index = (index + 1) % size;
093: backend = (DatabaseBackend) backends.get(index);
094: maxTries--;
095: } while ((!backend.isReadEnabled() && maxTries >= 0));
096: }
097:
098: if (maxTries < 0)
099: throw new SQLException(Translate.get(
100: "loadbalancer.execute.no.backend.enabled",
101: request.getId()));
102: } catch (RuntimeException e) {
103: String msg = Translate.get(
104: "loadbalancer.execute.find.backend.failed",
105: new String[] {
106: request.getSqlShortForm(vdb
107: .getSqlShortFormLength()),
108: e.getMessage() });
109: logger.error(msg, e);
110: throw new SQLException(msg);
111: } finally {
112: vdb.releaseReadLockBackendLists();
113: }
114: return backend;
115: }
116:
117: /**
118: * Choose a backend using a round-robin algorithm for write request execution.
119: *
120: * @param request request to execute
121: * @return the chosen backend
122: * @throws SQLException if an error occurs
123: */
124: public DatabaseBackend chooseBackendForWriteRequest(
125: AbstractWriteRequest request) throws SQLException {
126: // Choose a backend
127: try {
128: vdb.acquireReadLockBackendLists();
129: } catch (InterruptedException e) {
130: String msg = Translate.get(
131: "loadbalancer.backendlist.acquire.readlock.failed",
132: e);
133: logger.error(msg);
134: throw new SQLException(msg);
135: }
136:
137: DatabaseBackend backend = null; // The backend that will execute the query
138:
139: // Note that vdb lock is released in the finally clause of this try/catch
140: // block
141: try {
142: ArrayList backends = vdb.getBackends();
143: int size = backends.size();
144:
145: if (size == 0)
146: throw new NoMoreBackendException(Translate.get(
147: "loadbalancer.execute.no.backend.available",
148: request.getId()));
149:
150: // Take the next backend
151: int maxTries = size;
152: synchronized (this ) {
153: do {
154: index = (index + 1) % size;
155: backend = (DatabaseBackend) backends.get(index);
156: maxTries--;
157: } while ((!backend.isWriteEnabled() || backend
158: .isDisabling())
159: && (maxTries >= 0));
160: }
161:
162: if (maxTries < 0)
163: throw new SQLException(Translate.get(
164: "loadbalancer.execute.no.backend.enabled",
165: request.getId()));
166: } catch (RuntimeException e) {
167: String msg = Translate.get(
168: "loadbalancer.execute.find.backend.failed",
169: new String[] {
170: request.getSqlShortForm(vdb
171: .getSqlShortFormLength()),
172: e.getMessage() });
173: logger.error(msg, e);
174: throw new SQLException(msg);
175: } finally {
176: vdb.releaseReadLockBackendLists();
177: }
178: return backend;
179: }
180:
181: /**
182: * @see org.continuent.sequoia.controller.loadbalancer.AbstractLoadBalancer#getInformation()
183: */
184: public String getInformation() {
185: // We don't lock since we don't need a top accurate value
186: int size = vdb.getBackends().size();
187:
188: if (size == 0)
189: return "ParallelDB Round-Robin Request load balancer: !!!Warning!!! No backend nodes found\n";
190: else
191: return "ParallelDB Round-Robin Request load balancer ("
192: + size + " backends)\n";
193: }
194:
195: /**
196: * @see org.continuent.sequoia.controller.loadbalancer.paralleldb.ParallelDB#getParallelDBXml()
197: */
198: public String getParallelDBXml() {
199: return "<" + DatabasesXmlTags.ELT_ParallelDB_RoundRobin + "/>";
200: }
201: }
|