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_LPRF load balancer. This load balancer
036: * chooses the node that has the least pending queries for read and write
037: * queries execution.
038: *
039: * @author <a href="mailto:Emmanuel.Cecchet@inria.fr">Emmanuel Cecchet </a>
040: * @version 1.0
041: */
042: public class ParallelDB_LPRF extends ParallelDB {
043:
044: /**
045: * Creates a new <code>ParallelDB_LPRF</code> object.
046: *
047: * @param vdb the virtual database this load balancer belongs to.
048: * @throws Exception if an error occurs
049: */
050: public ParallelDB_LPRF(VirtualDatabase vdb) throws Exception {
051: super (vdb);
052: }
053:
054: /**
055: * @see org.continuent.sequoia.controller.loadbalancer.paralleldb.ParallelDB#chooseBackendForReadRequest(org.continuent.sequoia.controller.requests.AbstractRequest)
056: */
057: public DatabaseBackend chooseBackendForReadRequest(
058: AbstractRequest request) throws SQLException {
059: // Choose a backend
060: try {
061: vdb.acquireReadLockBackendLists();
062: } catch (InterruptedException e) {
063: String msg = Translate.get(
064: "loadbalancer.backendlist.acquire.readlock.failed",
065: e);
066: logger.error(msg);
067: throw new SQLException(msg);
068: }
069:
070: DatabaseBackend backend = null; // The backend that will execute the query
071:
072: // Note that vdb lock is released in the finally clause of this try/catch
073: // block
074: try {
075: ArrayList backends = vdb.getBackends();
076: int size = backends.size();
077:
078: if (size == 0)
079: throw new NoMoreBackendException(Translate.get(
080: "loadbalancer.execute.no.backend.available",
081: request.getId()));
082:
083: // Choose the backend that has the least pending requests
084: int leastRequests = 0;
085: for (int i = 0; i < size; i++) {
086: DatabaseBackend b = (DatabaseBackend) backends.get(i);
087: if (b.isReadEnabled()) {
088: int pending = b.getPendingRequests().size();
089: if ((backend == null) || (pending < leastRequests)) {
090: backend = b;
091: if (pending == 0)
092: break; // Stop here we will never find a less loaded node
093: else
094: leastRequests = pending;
095: }
096: }
097: }
098:
099: if (backend == null)
100: throw new SQLException(Translate.get(
101: "loadbalancer.execute.no.backend.enabled",
102: request.getId()));
103: } catch (RuntimeException e) {
104: String msg = Translate.get(
105: "loadbalancer.execute.find.backend.failed",
106: new String[] {
107: request.getSqlShortForm(vdb
108: .getSqlShortFormLength()),
109: e.getMessage() });
110: logger.error(msg, e);
111: throw new SQLException(msg);
112: } finally {
113: vdb.releaseReadLockBackendLists();
114: }
115:
116: return backend;
117: }
118:
119: /**
120: * @see org.continuent.sequoia.controller.loadbalancer.paralleldb.ParallelDB#chooseBackendForWriteRequest(org.continuent.sequoia.controller.requests.AbstractWriteRequest)
121: */
122: public DatabaseBackend chooseBackendForWriteRequest(
123: AbstractWriteRequest request) throws SQLException {
124: // Choose a backend
125: try {
126: vdb.acquireReadLockBackendLists();
127: } catch (InterruptedException e) {
128: String msg = Translate.get(
129: "loadbalancer.backendlist.acquire.readlock.failed",
130: e);
131: logger.error(msg);
132: throw new SQLException(msg);
133: }
134:
135: DatabaseBackend backend = null; // The backend that will execute the query
136:
137: // Note that vdb lock is released in the finally clause of this try/catch
138: // block
139: try {
140: ArrayList backends = vdb.getBackends();
141: int size = backends.size();
142:
143: if (size == 0)
144: throw new NoMoreBackendException(Translate.get(
145: "loadbalancer.execute.no.backend.available",
146: request.getId()));
147:
148: // Choose the backend that has the least pending requests
149: int leastRequests = 0;
150: for (int i = 0; i < size; i++) {
151: DatabaseBackend b = (DatabaseBackend) backends.get(i);
152: if (b.isWriteEnabled() && !b.isDisabling()) {
153: int pending = b.getPendingRequests().size();
154: if ((backend == null) || (pending < leastRequests)) {
155: backend = b;
156: if (pending == 0)
157: break; // Stop here we will never find a less loaded node
158: else
159: leastRequests = pending;
160: }
161: }
162: }
163:
164: if (backend == null) {
165: throw new SQLException(Translate.get(
166: "loadbalancer.execute.no.backend.enabled",
167: request.getId()));
168: }
169: } catch (RuntimeException e) {
170: String msg = Translate.get(
171: "loadbalancer.execute.find.backend.failed",
172: new String[] {
173: request.getSqlShortForm(vdb
174: .getSqlShortFormLength()),
175: e.getMessage() });
176: logger.error(msg, e);
177: throw new SQLException(msg);
178: } finally {
179: vdb.releaseReadLockBackendLists();
180: }
181:
182: return backend;
183: }
184:
185: /**
186: * @see org.continuent.sequoia.controller.loadbalancer.AbstractLoadBalancer#getInformation()
187: */
188: public String getInformation() {
189: // We don't lock since we don't need a top accurate value
190: int size = vdb.getBackends().size();
191:
192: if (size == 0)
193: return "ParallelDB Least Pending Request First Request load balancer: !!!Warning!!! No backend nodes found\n";
194: else
195: return "ParallelDB Least Pending Request First Request load balancer ("
196: + size + " backends)\n";
197: }
198:
199: /**
200: * @see org.continuent.sequoia.controller.loadbalancer.paralleldb.ParallelDB#getParallelDBXml()
201: */
202: public String getParallelDBXml() {
203: return "<"
204: + DatabasesXmlTags.ELT_ParallelDB_LeastPendingRequestsFirst
205: + "/>";
206: }
207: }
|