KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > continuent > sequoia > controller > loadbalancer > paralleldb > ParallelDB


1 /**
2  * Sequoia: Database clustering technology.
3  * Copyright (C) 2002-2004 French National Institute For Research In Computer
4  * Science And Control (INRIA).
5  * Copyright (C) 2005 AmicoSoft, Inc. dba Emic Networks
6  * Contact: sequoia@continuent.org
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19
20
21  * Free Software Foundation; either version 2.1 of the License, or any later
22  * version.
23  *
24  * This library is distributed in the hope that it will be useful, but WITHOUT
25  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
26  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
27  * for more details.
28  *
29  * You should have received a copy of the GNU Lesser General Public License
30  * along with this library; if not, write to the Free Software Foundation,
31  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
32  *
33  * Initial developer(s): Emmanuel Cecchet.
34  * Contributor(s): Jaco Swart, Jean-Bernard van Zuylen.
35  */

36
37 package org.continuent.sequoia.controller.loadbalancer.paralleldb;
38
39 import java.sql.Connection JavaDoc;
40 import java.sql.SQLException JavaDoc;
41 import java.sql.Savepoint JavaDoc;
42 import java.util.Hashtable JavaDoc;
43 import java.util.List JavaDoc;
44
45 import org.continuent.sequoia.common.exceptions.BadConnectionException;
46 import org.continuent.sequoia.common.exceptions.NoMoreBackendException;
47 import org.continuent.sequoia.common.exceptions.NoTransactionStartWhenDisablingException;
48 import org.continuent.sequoia.common.exceptions.SQLExceptionFactory;
49 import org.continuent.sequoia.common.exceptions.UnreachableBackendException;
50 import org.continuent.sequoia.common.i18n.Translate;
51 import org.continuent.sequoia.common.log.Trace;
52 import org.continuent.sequoia.common.xml.DatabasesXmlTags;
53 import org.continuent.sequoia.controller.backend.DatabaseBackend;
54 import org.continuent.sequoia.controller.backend.result.ControllerResultSet;
55 import org.continuent.sequoia.controller.backend.result.ExecuteResult;
56 import org.continuent.sequoia.controller.backend.result.ExecuteUpdateResult;
57 import org.continuent.sequoia.controller.backend.result.GeneratedKeysResult;
58 import org.continuent.sequoia.controller.cache.metadata.MetadataCache;
59 import org.continuent.sequoia.controller.connection.AbstractConnectionManager;
60 import org.continuent.sequoia.controller.connection.PooledConnection;
61 import org.continuent.sequoia.controller.loadbalancer.AbstractLoadBalancer;
62 import org.continuent.sequoia.controller.loadbalancer.AllBackendsFailedException;
63 import org.continuent.sequoia.controller.requestmanager.RAIDbLevels;
64 import org.continuent.sequoia.controller.requestmanager.TransactionMetaData;
65 import org.continuent.sequoia.controller.requests.AbstractRequest;
66 import org.continuent.sequoia.controller.requests.AbstractWriteRequest;
67 import org.continuent.sequoia.controller.requests.ParsingGranularities;
68 import org.continuent.sequoia.controller.requests.SelectRequest;
69 import org.continuent.sequoia.controller.requests.StoredProcedure;
70 import org.continuent.sequoia.controller.requests.UnknownReadRequest;
71 import org.continuent.sequoia.controller.virtualdatabase.VirtualDatabase;
72
73 /**
74  * This class defines a ParallelDB
75  *
76  * @author <a HREF="mailto:Emmanuel.Cecchet@inria.fr">Emmanuel Cecchet </a>
77  * @author <a HREF="mailto:jbvanzuylen@transwide.com">Jean-Bernard van Zuylen
78  * </a>
79  * @version 1.0
80  */

81 /**
82  * These are generic functions for all ParallelDB load balancers.
83  * <p>
84  * Read and write queries are load balanced on the backends without any
85  * replication (assuming that the underlying parallel database takes care of
86  * data replication). The load balancers provide failover for reads and writes.
87  *
88  * @author <a HREF="mailto:Emmanuel.Cecchet@inria.fr">Emmanuel Cecchet </a>
89  * @author <a HREF="mailto:jaco.swart@iblocks.co.uk">Jaco Swart </a>
90  * @version 1.0
91  */

92 public abstract class ParallelDB extends AbstractLoadBalancer
93 {
94   // transaction id -> DatabaseBackend
95
private Hashtable JavaDoc backendPerTransactionId;
96   private int numberOfEnabledBackends = 0;
97
98   static Trace endUserLogger = Trace
99                                                 .getLogger("org.continuent.sequoia.enduser");
100
101   /**
102    * Creates a new <code>ParallelDB</code> load balancer with NO_PARSING and a
103    * SingleDB RAIDb level.
104    *
105    * @param vdb the virtual database this load balancer belongs to.
106    * @throws SQLException if an error occurs
107    */

108   public ParallelDB(VirtualDatabase vdb) throws SQLException JavaDoc
109   {
110     super(vdb, RAIDbLevels.SingleDB, ParsingGranularities.NO_PARSING);
111     backendPerTransactionId = new Hashtable JavaDoc();
112   }
113
114   //
115
// Request handling
116
//
117

118   /**
119    * Choose a backend using the implementation specific load balancing algorithm
120    * for read request execution.
121    *
122    * @param request request to execute
123    * @return the chosen backend
124    * @throws SQLException if an error occurs
125    */

126   public abstract DatabaseBackend chooseBackendForReadRequest(
127       AbstractRequest request) throws SQLException JavaDoc;
128
129   /**
130    * Choose a backend using the implementation specific load balancing algorithm
131    * for write request execution.
132    *
133    * @param request request to execute
134    * @return the chosen backend
135    * @throws SQLException if an error occurs
136    */

137   public abstract DatabaseBackend chooseBackendForWriteRequest(
138       AbstractWriteRequest request) throws SQLException JavaDoc;
139
140   /**
141    * @see org.continuent.sequoia.controller.loadbalancer.AbstractLoadBalancer#statementExecuteQuery(SelectRequest,
142    * MetadataCache)
143    */

144   public ControllerResultSet statementExecuteQuery(SelectRequest request,
145       MetadataCache metadataCache) throws SQLException JavaDoc
146   {
147     DatabaseBackend backend;
148     if (request.isAutoCommit())
149       backend = chooseBackendForReadRequest(request);
150     else
151       backend = (DatabaseBackend) backendPerTransactionId.get(new Long JavaDoc(request
152           .getTransactionId()));
153
154     if (backend == null)
155       throw new SQLException JavaDoc(Translate.get(
156           "loadbalancer.execute.no.backend.found", request.getSqlShortForm(vdb
157               .getSqlShortFormLength())));
158
159     ControllerResultSet rs = null;
160     // Execute the request on the chosen backend
161
try
162     {
163       rs = executeStatementExecuteQueryOnBackend(request, backend,
164           metadataCache);
165     }
166     catch (UnreachableBackendException urbe)
167     {
168       // Notify failure in recovery log
169
if (recoveryLog != null)
170         recoveryLog.logRequestCompletion(request.getLogId(), false, request
171             .getExecTimeInMs());
172
173       // Try to execute query on different backend
174
return statementExecuteQuery(request, metadataCache);
175     }
176     catch (SQLException JavaDoc se)
177     {
178       // Notify failure in recovery log
179
if (recoveryLog != null)
180         recoveryLog.logRequestCompletion(request.getLogId(), false, request
181             .getExecTimeInMs());
182
183       String JavaDoc msg = Translate.get("loadbalancer.request.failed", new String JavaDoc[]{
184           String.valueOf(request.getId()), se.getMessage()});
185       if (logger.isInfoEnabled())
186         logger.info(msg);
187       throw new SQLException JavaDoc(msg);
188     }
189     catch (RuntimeException JavaDoc e)
190     {
191       // Notify failure in recovery log
192
if (recoveryLog != null)
193         recoveryLog.logRequestCompletion(request.getLogId(), false, request
194             .getExecTimeInMs());
195
196       String JavaDoc msg = Translate.get("loadbalancer.request.failed.on.backend",
197           new String JavaDoc[]{request.getSqlShortForm(vdb.getSqlShortFormLength()),
198               backend.getName(), e.getMessage()});
199       logger.error(msg, e);
200       throw new SQLException JavaDoc(msg);
201     }
202
203     return rs;
204   }
205
206   /**
207    * @see org.continuent.sequoia.controller.loadbalancer.AbstractLoadBalancer#statementExecuteUpdate(org.continuent.sequoia.controller.requests.AbstractWriteRequest)
208    */

209   public ExecuteUpdateResult statementExecuteUpdate(AbstractWriteRequest request)
210       throws AllBackendsFailedException, SQLException JavaDoc
211   {
212     // Handle macros
213
handleMacros(request);
214
215     // Log lazy begin if needed
216
if (request.isLazyTransactionStart())
217       this.vdb.getRequestManager().logLazyTransactionBegin(
218           request.getTransactionId());
219
220     // Log request
221
if (recoveryLog != null)
222       recoveryLog.logRequestExecuting(request);
223
224     DatabaseBackend backend;
225     if (request.isAutoCommit())
226       backend = chooseBackendForWriteRequest(request);
227     else
228       backend = (DatabaseBackend) backendPerTransactionId.get(new Long JavaDoc(request
229           .getTransactionId()));
230
231     if (backend == null)
232       throw new SQLException JavaDoc(Translate.get(
233           "loadbalancer.execute.no.backend.found", request.getSqlShortForm(vdb
234               .getSqlShortFormLength())));
235
236     ExecuteUpdateResult result;
237     // Execute the request on the chosen backend
238
try
239     {
240       result = executeStatementExecuteUpdateOnBackend(request, backend);
241     }
242     catch (UnreachableBackendException urbe)
243     {
244       // Notify failure in recovery log
245
if (recoveryLog != null)
246         recoveryLog.logRequestCompletion(request.getLogId(), false, request
247             .getExecTimeInMs());
248
249       // Try to execute query on different backend
250
return statementExecuteUpdate(request);
251     }
252     catch (SQLException JavaDoc se)
253     {
254       // Notify failure in recovery log
255
if (recoveryLog != null)
256         recoveryLog.logRequestCompletion(request.getLogId(), false, request
257             .getExecTimeInMs());
258
259       String JavaDoc msg = Translate.get("loadbalancer.request.failed", new String JavaDoc[]{
260           String.valueOf(request.getId()), se.getMessage()});
261       if (logger.isInfoEnabled())
262         logger.info(msg);
263       throw new SQLException JavaDoc(msg);
264     }
265     catch (RuntimeException JavaDoc e)
266     {
267       // Notify failure in recovery log
268
if (recoveryLog != null)
269         recoveryLog.logRequestCompletion(request.getLogId(), false, request
270             .getExecTimeInMs());
271
272       String JavaDoc msg = Translate.get("loadbalancer.request.failed.on.backend",
273           new String JavaDoc[]{request.getSqlShortForm(vdb.getSqlShortFormLength()),
274               backend.getName(), e.getMessage()});
275       logger.error(msg, e);
276       throw new SQLException JavaDoc(msg);
277     }
278
279     return result;
280   }
281
282   /**
283    * @see org.continuent.sequoia.controller.loadbalancer.AbstractLoadBalancer#statementExecuteUpdateWithKeys(AbstractWriteRequest,
284    * MetadataCache)
285    */

286   public GeneratedKeysResult statementExecuteUpdateWithKeys(
287       AbstractWriteRequest request, MetadataCache metadataCache)
288       throws AllBackendsFailedException, SQLException JavaDoc
289   {
290     // Handle macros
291
handleMacros(request);
292
293     // Log lazy begin if needed
294
if (request.isLazyTransactionStart())
295       this.vdb.getRequestManager().logLazyTransactionBegin(
296           request.getTransactionId());
297
298     // Log request
299
if (recoveryLog != null)
300       recoveryLog.logRequestExecuting(request);
301
302     DatabaseBackend backend;
303     if (request.isAutoCommit())
304       backend = chooseBackendForWriteRequest(request);
305     else
306       backend = (DatabaseBackend) backendPerTransactionId.get(new Long JavaDoc(request
307           .getTransactionId()));
308
309     if (backend == null)
310       throw new SQLException JavaDoc(Translate.get(
311           "loadbalancer.execute.no.backend.found", request.getSqlShortForm(vdb
312               .getSqlShortFormLength())));
313
314     GeneratedKeysResult rs;
315     // Execute the request on the chosen backend
316
try
317     {
318       rs = executeStatementExecuteUpdateWithKeysOnBackend(request, backend,
319           metadataCache);
320     }
321     catch (UnreachableBackendException urbe)
322     {
323       // Notify failure in recovery log
324
if (recoveryLog != null)
325         recoveryLog.logRequestCompletion(request.getLogId(), false, request
326             .getExecTimeInMs());
327
328       // Try to execute query on different backend
329
return statementExecuteUpdateWithKeys(request, metadataCache);
330     }
331     catch (SQLException JavaDoc se)
332     {
333       // Notify failure in recovery log
334
if (recoveryLog != null)
335         recoveryLog.logRequestCompletion(request.getLogId(), false, request
336             .getExecTimeInMs());
337
338       String JavaDoc msg = Translate.get("loadbalancer.request.failed", new String JavaDoc[]{
339           String.valueOf(request.getId()), se.getMessage()});
340       if (logger.isInfoEnabled())
341         logger.info(msg);
342       throw new SQLException JavaDoc(msg);
343     }
344     catch (RuntimeException JavaDoc e)
345     {
346       // Notify failure in recovery log
347
if (recoveryLog != null)
348         recoveryLog.logRequestCompletion(request.getLogId(), false, request
349             .getExecTimeInMs());
350
351       String JavaDoc msg = Translate.get("loadbalancer.request.failed.on.backend",
352           new String JavaDoc[]{request.getSqlShortForm(vdb.getSqlShortFormLength()),
353               backend.getName(), e.getMessage()});
354       logger.error(msg, e);
355       throw new SQLException JavaDoc(msg);
356     }
357
358     return rs;
359   }
360
361   /**
362    * @see org.continuent.sequoia.controller.loadbalancer.AbstractLoadBalancer#statementExecute(AbstractRequest,
363    * MetadataCache)
364    */

365   public ExecuteResult statementExecute(AbstractRequest request,
366       MetadataCache metadataCache) throws SQLException JavaDoc,
367       AllBackendsFailedException
368   {
369     // Handle macros
370
handleMacros(request);
371
372     // Log lazy begin if needed
373
if (request.isLazyTransactionStart())
374       this.vdb.getRequestManager().logLazyTransactionBegin(
375           request.getTransactionId());
376
377     // Log request
378
if (recoveryLog != null)
379       recoveryLog.logRequestExecuting(request);
380
381     DatabaseBackend backend;
382     if (request.isAutoCommit())
383       backend = chooseBackendForReadRequest(request);
384     else
385       backend = (DatabaseBackend) backendPerTransactionId.get(new Long JavaDoc(request
386           .getTransactionId()));
387
388     if (backend == null)
389       throw new SQLException JavaDoc(Translate.get(
390           "loadbalancer.storedprocedure.no.backend.found", request
391               .getSqlShortForm(vdb.getSqlShortFormLength())));
392
393     ExecuteResult rs = null;
394     // Execute the request on the chosen backend
395
try
396     {
397       rs = executeStatementExecuteOnBackend(request, backend, metadataCache);
398     }
399     catch (UnreachableBackendException urbe)
400     {
401       // Notify failure in recovery log
402
recoveryLog.logRequestCompletion(request.getLogId(), false, request
403           .getExecTimeInMs());
404
405       // Try to execute query on different backend
406
return statementExecute(request, metadataCache);
407     }
408     catch (SQLException JavaDoc se)
409     {
410       // Notify failure in recovery log
411
recoveryLog.logRequestCompletion(request.getLogId(), false, request
412           .getExecTimeInMs());
413
414       String JavaDoc msg = Translate.get("loadbalancer.storedprocedure.failed",
415           new String JavaDoc[]{String.valueOf(request.getId()), se.getMessage()});
416       if (logger.isInfoEnabled())
417         logger.info(msg);
418       throw new SQLException JavaDoc(msg);
419     }
420     catch (RuntimeException JavaDoc e)
421     {
422       // Notify failure in recovery log
423
recoveryLog.logRequestCompletion(request.getLogId(), false, request
424           .getExecTimeInMs());
425
426       String JavaDoc msg = Translate.get(
427           "loadbalancer.storedprocedure.failed.on.backend", new String JavaDoc[]{
428               request.getSqlShortForm(vdb.getSqlShortFormLength()),
429               backend.getName(), e.getMessage()});
430       logger.error(msg, e);
431       throw new SQLException JavaDoc(msg);
432     }
433
434     return rs;
435   }
436
437   /**
438    * @see org.continuent.sequoia.controller.loadbalancer.AbstractLoadBalancer#readOnlyCallableStatementExecuteQuery(StoredProcedure,
439    * MetadataCache)
440    */

441   public ControllerResultSet readOnlyCallableStatementExecuteQuery(
442       StoredProcedure proc, MetadataCache metadataCache) throws SQLException JavaDoc
443   {
444     return callableStatementExecuteQuery(proc, metadataCache);
445   }
446
447   /**
448    * @see org.continuent.sequoia.controller.loadbalancer.AbstractLoadBalancer#readOnlyCallableStatementExecute(StoredProcedure,
449    * MetadataCache)
450    */

451   public ExecuteResult readOnlyCallableStatementExecute(StoredProcedure proc,
452       MetadataCache metadataCache) throws SQLException JavaDoc
453   {
454     return callableStatementExecute(proc, metadataCache);
455   }
456
457   /**
458    * @see org.continuent.sequoia.controller.loadbalancer.AbstractLoadBalancer#callableStatementExecuteQuery(StoredProcedure,
459    * MetadataCache)
460    */

461   public ControllerResultSet callableStatementExecuteQuery(
462       StoredProcedure proc, MetadataCache metadataCache) throws SQLException JavaDoc
463   {
464     // Handle macros
465
handleMacros(proc);
466
467     // Log lazy begin if needed
468
if (proc.isLazyTransactionStart())
469       this.vdb.getRequestManager().logLazyTransactionBegin(
470           proc.getTransactionId());
471
472     // Log request
473
if (recoveryLog != null)
474       recoveryLog.logRequestExecuting(proc);
475
476     DatabaseBackend backend;
477     if (proc.isAutoCommit())
478       backend = chooseBackendForReadRequest(proc);
479     else
480       backend = (DatabaseBackend) backendPerTransactionId.get(new Long JavaDoc(proc
481           .getTransactionId()));
482
483     if (backend == null)
484       throw new SQLException JavaDoc(Translate.get(
485           "loadbalancer.storedprocedure.no.backend.found", proc
486               .getSqlShortForm(vdb.getSqlShortFormLength())));
487
488     ControllerResultSet rs = null;
489     // Execute the request on the chosen backend
490
try
491     {
492       rs = executeCallableStatementExecuteQueryOnBackend(proc, backend,
493           metadataCache);
494     }
495     catch (UnreachableBackendException urbe)
496     {
497       // Notify failure in recovery log
498
if (recoveryLog != null)
499         recoveryLog.logRequestCompletion(proc.getLogId(), false, proc
500             .getExecTimeInMs());
501
502       // Try to execute query on different backend
503
return callableStatementExecuteQuery(proc, metadataCache);
504     }
505     catch (SQLException JavaDoc se)
506     {
507       // Notify failure in recovery log
508
if (recoveryLog != null)
509         recoveryLog.logRequestCompletion(proc.getLogId(), false, proc
510             .getExecTimeInMs());
511
512       String JavaDoc msg = Translate.get("loadbalancer.storedprocedure.failed",
513           new String JavaDoc[]{String.valueOf(proc.getId()), se.getMessage()});
514       if (logger.isInfoEnabled())
515         logger.info(msg);
516       throw new SQLException JavaDoc(msg);
517     }
518     catch (RuntimeException JavaDoc e)
519     {
520       // Notify failure in recovery log
521
if (recoveryLog != null)
522         recoveryLog.logRequestCompletion(proc.getLogId(), false, proc
523             .getExecTimeInMs());
524
525       String JavaDoc msg = Translate.get(
526           "loadbalancer.storedprocedure.failed.on.backend", new String JavaDoc[]{
527               proc.getSqlShortForm(vdb.getSqlShortFormLength()),
528               backend.getName(), e.getMessage()});
529       logger.error(msg, e);
530       throw new SQLException JavaDoc(msg);
531     }
532
533     return rs;
534   }
535
536   /**
537    * @see org.continuent.sequoia.controller.loadbalancer.AbstractLoadBalancer#callableStatementExecuteUpdate(org.continuent.sequoia.controller.requests.StoredProcedure)
538    */

539   public ExecuteUpdateResult callableStatementExecuteUpdate(StoredProcedure proc)
540       throws SQLException JavaDoc
541   {
542     // Handle macros
543
handleMacros(proc);
544
545     // Log lazy begin if needed
546
if (proc.isLazyTransactionStart())
547       this.vdb.getRequestManager().logLazyTransactionBegin(
548           proc.getTransactionId());
549
550     // Log request
551
if (recoveryLog != null)
552       recoveryLog.logRequestExecuting(proc);
553
554     DatabaseBackend backend;
555     if (proc.isAutoCommit())
556       backend = chooseBackendForReadRequest(proc);
557     else
558       backend = (DatabaseBackend) backendPerTransactionId.get(new Long JavaDoc(proc
559           .getTransactionId()));
560
561     if (backend == null)
562       throw new SQLException JavaDoc(Translate.get(
563           "loadbalancer.storedprocedure.no.backend.found", proc
564               .getSqlShortForm(vdb.getSqlShortFormLength())));
565
566     ExecuteUpdateResult result;
567     // Execute the request on the chosen backend
568
try
569     {
570       result = executeCallableStatementExecuteUpdateOnBackend(proc, backend);
571     }
572     catch (UnreachableBackendException urbe)
573     {
574       // Notify failure in recovery log
575
if (recoveryLog != null)
576         recoveryLog.logRequestCompletion(proc.getLogId(), false, proc
577             .getExecTimeInMs());
578
579       // Try to execute query on different backend
580
return callableStatementExecuteUpdate(proc);
581     }
582     catch (SQLException JavaDoc se)
583     {
584       // Notify failure in recovery log
585
if (recoveryLog != null)
586         recoveryLog.logRequestCompletion(proc.getLogId(), false, proc
587             .getExecTimeInMs());
588
589       String JavaDoc msg = Translate.get("loadbalancer.storedprocedure.failed",
590           new String JavaDoc[]{String.valueOf(proc.getId()), se.getMessage()});
591       if (logger.isInfoEnabled())
592         logger.info(msg);
593       throw new SQLException JavaDoc(msg);
594     }
595     catch (RuntimeException JavaDoc e)
596     {
597       // Notify failure in recovery log
598
if (recoveryLog != null)
599         recoveryLog.logRequestCompletion(proc.getLogId(), false, proc
600             .getExecTimeInMs());
601
602       String JavaDoc msg = Translate.get(
603           "loadbalancer.storedprocedure.failed.on.backend", new String JavaDoc[]{
604               proc.getSqlShortForm(vdb.getSqlShortFormLength()),
605               backend.getName(), e.getMessage()});
606       logger.error(msg, e);
607       throw new SQLException JavaDoc(msg);
608     }
609
610     return result;
611   }
612
613   /**
614    * @see org.continuent.sequoia.controller.loadbalancer.AbstractLoadBalancer#callableStatementExecute(StoredProcedure,
615    * MetadataCache)
616    */

617   public ExecuteResult callableStatementExecute(StoredProcedure proc,
618       MetadataCache metadataCache) throws SQLException JavaDoc
619   {
620     // Handle macros
621
handleMacros(proc);
622
623     // Log lazy begin if needed
624
if (proc.isLazyTransactionStart())
625       this.vdb.getRequestManager().logLazyTransactionBegin(
626           proc.getTransactionId());
627
628     // Log request
629
if (recoveryLog != null)
630       recoveryLog.logRequestExecuting(proc);
631
632     DatabaseBackend backend;
633     if (proc.isAutoCommit())
634       backend = chooseBackendForReadRequest(proc);
635     else
636       backend = (DatabaseBackend) backendPerTransactionId.get(new Long JavaDoc(proc
637           .getTransactionId()));
638
639     if (backend == null)
640       throw new SQLException JavaDoc(Translate.get(
641           "loadbalancer.storedprocedure.no.backend.found", proc
642               .getSqlShortForm(vdb.getSqlShortFormLength())));
643
644     ExecuteResult rs = null;
645     // Execute the request on the chosen backend
646
try
647     {
648       rs = executeCallableStatementExecuteOnBackend(proc, backend,
649           metadataCache);
650     }
651     catch (UnreachableBackendException urbe)
652     {
653       // Notify failure in recovery log
654
if (recoveryLog != null)
655         recoveryLog.logRequestCompletion(proc.getLogId(), false, proc
656             .getExecTimeInMs());
657
658       // Try to execute query on different backend
659
ExecuteResult result = callableStatementExecute(proc, metadataCache);
660
661       return result;
662     }
663     catch (SQLException JavaDoc se)
664     {
665       // Notify failure in recovery log
666
if (recoveryLog != null)
667         recoveryLog.logRequestCompletion(proc.getLogId(), false, proc
668             .getExecTimeInMs());
669
670       String JavaDoc msg = Translate.get("loadbalancer.storedprocedure.failed",
671           new String JavaDoc[]{String.valueOf(proc.getId()), se.getMessage()});
672       if (logger.isInfoEnabled())
673         logger.info(msg);
674       throw new SQLException JavaDoc(msg);
675     }
676     catch (RuntimeException JavaDoc e)
677     {
678       // Notify failure in recovery log
679
if (recoveryLog != null)
680         recoveryLog.logRequestCompletion(proc.getLogId(), false, proc
681             .getExecTimeInMs());
682
683       String JavaDoc msg = Translate.get(
684           "loadbalancer.storedprocedure.failed.on.backend", new String JavaDoc[]{
685               proc.getSqlShortForm(vdb.getSqlShortFormLength()),
686               backend.getName(), e.getMessage()});
687       logger.error(msg, e);
688       throw new SQLException JavaDoc(msg);
689     }
690
691     return rs;
692   }
693
694   /**
695    * Execute a read request on the selected backend.
696    *
697    * @param request the request to execute
698    * @param backend the backend that will execute the request
699    * @param metadataCache MetadataCache (null if none)
700    * @return the ControllerResultSet
701    * @throws SQLException if an error occurs
702    */

703   private ControllerResultSet executeStatementExecuteQueryOnBackend(
704       SelectRequest request, DatabaseBackend backend,
705       MetadataCache metadataCache) throws SQLException JavaDoc,
706       UnreachableBackendException
707   {
708     // Ok, we have a backend, let's execute the request
709
AbstractConnectionManager cm = backend.getConnectionManager(request
710         .getLogin());
711
712     // Sanity check
713
if (cm == null)
714     {
715       String JavaDoc msg = Translate.get("loadbalancer.connectionmanager.not.found",
716           new String JavaDoc[]{request.getLogin(), backend.getName()});
717       logger.error(msg);
718       throw new SQLException JavaDoc(msg);
719     }
720
721     // Execute the query
722
if (request.isAutoCommit())
723     {
724       ControllerResultSet rs = null;
725       boolean badConnection;
726       do
727       {
728         badConnection = false;
729         // Use a connection just for this request
730
PooledConnection pc = null;
731         try
732         {
733           pc = cm.retrieveConnectionInAutoCommit(request);
734         }
735         catch (UnreachableBackendException e1)
736         {
737           String JavaDoc msg = Translate.get(
738               "loadbalancer.backend.disabling.unreachable", backend.getName());
739           logger.error(msg);
740           endUserLogger.error(msg);
741           disableBackend(backend, true);
742           throw new UnreachableBackendException(Translate.get(
743               "loadbalancer.backend.unreacheable", backend.getName()));
744         }
745
746         // Sanity check
747
if (pc == null)
748           throw new SQLException JavaDoc(Translate.get(
749               "loadbalancer.backend.no.connection", backend.getName()));
750
751         // Execute Query
752
try
753         {
754           rs = executeStatementExecuteQueryOnBackend(request, backend, null, pc
755               .getConnection(), metadataCache);
756           cm.releaseConnectionInAutoCommit(request, pc);
757         }
758         catch (BadConnectionException e)
759         { // Get rid of the bad connection
760
cm.deleteConnection(pc);
761           badConnection = true;
762         }
763         catch (Throwable JavaDoc e)
764         {
765           cm.releaseConnectionInAutoCommit(request, pc);
766           throw new SQLException JavaDoc(Translate.get(
767               "loadbalancer.request.failed.on.backend", new String JavaDoc[]{
768                   request.getSqlShortForm(vdb.getSqlShortFormLength()),
769                   backend.getName(), e.getMessage()}));
770         }
771       }
772       while (badConnection);
773       if (logger.isDebugEnabled())
774         logger.debug(Translate.get("loadbalancer.execute.on", new String JavaDoc[]{
775             String.valueOf(request.getId()), backend.getName()}));
776       return rs;
777     }
778     else
779     { // Inside a transaction
780
Connection JavaDoc c;
781       long tid = request.getTransactionId();
782
783       try
784       {
785         c = backend
786             .getConnectionForTransactionAndLazyBeginIfNeeded(request, cm);
787       }
788       catch (UnreachableBackendException e1)
789       {
790         String JavaDoc msg = Translate.get(
791             "loadbalancer.backend.disabling.unreachable", backend.getName());
792         logger.error(msg);
793         endUserLogger.error(msg);
794         disableBackend(backend, true);
795         throw new SQLException JavaDoc(Translate.get(
796             "loadbalancer.backend.unreacheable", backend.getName()));
797       }
798       catch (NoTransactionStartWhenDisablingException e)
799       {
800         String JavaDoc msg = Translate.get("loadbalancer.backend.is.disabling",
801             new String JavaDoc[]{request.getSqlShortForm(vdb.getSqlShortFormLength()),
802                 backend.getName()});
803         logger.error(msg);
804         throw new SQLException JavaDoc(msg);
805       }
806
807       // Sanity check
808
if (c == null)
809         throw new SQLException JavaDoc(Translate.get(
810             "loadbalancer.unable.retrieve.connection", new String JavaDoc[]{
811                 String.valueOf(tid), backend.getName()}));
812
813       // Execute Query
814
ControllerResultSet rs = null;
815       try
816       {
817         rs = executeStatementExecuteQueryOnBackend(request, backend, null, c,
818             metadataCache);
819       }
820       catch (BadConnectionException e)
821       { // Connection failed, so did the transaction
822
// Disable the backend.
823
cm.deleteConnection(tid);
824         String JavaDoc msg = Translate.get(
825             "loadbalancer.backend.disabling.connection.failure", backend
826                 .getName());
827         logger.error(msg);
828         endUserLogger.error(msg);
829         disableBackend(backend, true);
830         throw new SQLException JavaDoc(msg);
831       }
832       catch (Throwable JavaDoc e)
833       {
834         throw new SQLException JavaDoc(Translate.get(
835             "loadbalancer.request.failed.on.backend", new String JavaDoc[]{
836                 request.getSqlShortForm(vdb.getSqlShortFormLength()),
837                 backend.getName(), e.getMessage()}));
838       }
839       if (logger.isDebugEnabled())
840         logger.debug(Translate.get("loadbalancer.execute.transaction.on",
841             new String JavaDoc[]{String.valueOf(tid), String.valueOf(request.getId()),
842                 backend.getName()}));
843       return rs;
844     }
845   }
846
847   /**
848    * Execute a write request on the selected backend.
849    *
850    * @param request the request to execute
851    * @param backend the backend that will execute the request
852    * @return the number of modified rows
853    * @throws SQLException if an error occurs
854    */

855   private ExecuteUpdateResult executeStatementExecuteUpdateOnBackend(
856       AbstractWriteRequest request, DatabaseBackend backend)
857       throws SQLException JavaDoc, UnreachableBackendException
858   {
859     if (backend == null)
860       throw new NoMoreBackendException(Translate.get(
861           "loadbalancer.execute.no.backend.available", request.getId()));
862
863     try
864     {
865       AbstractConnectionManager cm = backend.getConnectionManager(request
866           .getLogin());
867       if (request.isAutoCommit())
868       { // Use a connection just for this request
869
PooledConnection c = null;
870         try
871         {
872           c = cm.retrieveConnectionInAutoCommit(request);
873         }
874         catch (UnreachableBackendException e1)
875         {
876           String JavaDoc backendName = backend.getName();
877           String JavaDoc msg = Translate.get(
878               "loadbalancer.backend.disabling.unreachable", backendName);
879           logger.error(msg);
880           endUserLogger.error(msg);
881           disableBackend(backend, true);
882           throw new UnreachableBackendException(Translate.get(
883               "loadbalancer.backend.unreacheable", backendName));
884         }
885
886         // Sanity check
887
if (c == null)
888           throw new UnreachableBackendException(Translate.get(
889               "loadbalancer.backend.no.connection", backend.getName()));
890
891         // Execute Query
892
ExecuteUpdateResult result;
893         try
894         {
895           result = executeStatementExecuteUpdateOnBackend(request, backend,
896               null, c.getConnection());
897         }
898         catch (Exception JavaDoc e)
899         {
900           throw new SQLException JavaDoc(Translate.get(
901               "loadbalancer.request.failed.on.backend", new String JavaDoc[]{
902                   request.getSqlShortForm(vdb.getSqlShortFormLength()),
903                   backend.getName(), e.getMessage()}));
904         }
905         finally
906         {
907           cm.releaseConnectionInAutoCommit(request, c);
908         }
909         return result;
910       }
911       else
912       { // Re-use the connection used by this transaction
913
PooledConnection c = cm.retrieveConnectionForTransaction(request
914             .getTransactionId());
915
916         // Sanity check
917
if (c == null)
918           throw new SQLException JavaDoc(Translate.get(
919               "loadbalancer.unable.retrieve.connection",
920               new String JavaDoc[]{String.valueOf(request.getTransactionId()),
921                   backend.getName()}));
922
923         // Execute Query
924
ExecuteUpdateResult result;
925         try
926         {
927           result = executeStatementExecuteUpdateOnBackend(request, backend,
928               null, c.getConnection());
929           return result;
930         }
931         catch (Exception JavaDoc e)
932         {
933           throw new SQLException JavaDoc(Translate.get(
934               "loadbalancer.request.failed.on.backend", new String JavaDoc[]{
935                   request.getSqlShortForm(vdb.getSqlShortFormLength()),
936                   backend.getName(), e.getMessage()}));
937         }
938       }
939     }
940     catch (RuntimeException JavaDoc e)
941     {
942       String JavaDoc msg = Translate.get("loadbalancer.request.failed.on.backend",
943           new String JavaDoc[]{request.getSqlShortForm(vdb.getSqlShortFormLength()),
944               backend.getName(), e.getMessage()});
945       logger.fatal(msg, e);
946       throw new SQLException JavaDoc(msg);
947     }
948   }
949
950   /**
951    * Execute a write request on the selected backend and return the
952    * autogenerated keys.
953    *
954    * @param request the request to execute
955    * @param backend the backend that will execute the request
956    * @param metadataCache MetadataCache (null if none)
957    * @return the ResultSet containing the auto-generated keys
958    * @throws SQLException if an error occurs
959    */

960   private GeneratedKeysResult executeStatementExecuteUpdateWithKeysOnBackend(
961       AbstractWriteRequest request, DatabaseBackend backend,
962       MetadataCache metadataCache) throws SQLException JavaDoc,
963       UnreachableBackendException
964   {
965     if (backend == null)
966       throw new NoMoreBackendException(Translate.get(
967           "loadbalancer.execute.no.backend.available", request.getId()));
968
969     if (!backend.getDriverCompliance().supportGetGeneratedKeys())
970       throw new SQLException JavaDoc(Translate.get(
971           "loadbalancer.backend.autogeneratedkeys.unsupported", backend
972               .getName()));
973
974     try
975     {
976       AbstractConnectionManager cm = backend.getConnectionManager(request
977           .getLogin());
978       if (request.isAutoCommit())
979       { // Use a connection just for this request
980
PooledConnection c = null;
981         try
982         {
983           c = cm.retrieveConnectionInAutoCommit(request);
984         }
985         catch (UnreachableBackendException e1)
986         {
987           String JavaDoc backendName = backend.getName();
988           String JavaDoc msg = Translate.get(
989               "loadbalancer.backend.disabling.unreachable", backendName);
990           logger.error(msg);
991           endUserLogger.error(msg);
992           disableBackend(backend, true);
993           throw new UnreachableBackendException(Translate.get(
994               "loadbalancer.backend.unreacheable", backendName));
995         }
996
997         // Sanity check
998
if (c == null)
999           throw new UnreachableBackendException(Translate.get(
1000              "loadbalancer.backend.no.connection", backend.getName()));
1001
1002        // Execute Query
1003
GeneratedKeysResult result;
1004        try
1005        {
1006          result = executeStatementExecuteUpdateWithKeysOnBackend(request,
1007              backend, null, c.getConnection(), metadataCache);
1008        }
1009        catch (Exception JavaDoc e)
1010        {
1011          throw new SQLException JavaDoc(Translate.get(
1012              "loadbalancer.request.failed.on.backend", new String JavaDoc[]{
1013                  request.getSqlShortForm(vdb.getSqlShortFormLength()),
1014                  backend.getName(), e.getMessage()}));
1015        }
1016        finally
1017        {
1018          cm.releaseConnectionInAutoCommit(request, c);
1019        }
1020        return result;
1021      }
1022      else
1023      { // Re-use the connection used by this transaction
1024
PooledConnection c = cm.retrieveConnectionForTransaction(request
1025            .getTransactionId());
1026
1027        // Sanity check
1028
if (c == null)
1029          throw new SQLException JavaDoc(Translate.get(
1030              "loadbalancer.unable.retrieve.connection",
1031              new String JavaDoc[]{String.valueOf(request.getTransactionId()),
1032                  backend.getName()}));
1033
1034        // Execute Query
1035
try
1036        {
1037          return executeStatementExecuteUpdateWithKeysOnBackend(request,
1038              backend, null, c.getConnection(), metadataCache);
1039        }
1040        catch (Exception JavaDoc e)
1041        {
1042          throw new SQLException JavaDoc(Translate.get(
1043              "loadbalancer.request.failed.on.backend", new String JavaDoc[]{
1044                  request.getSqlShortForm(vdb.getSqlShortFormLength()),
1045                  backend.getName(), e.getMessage()}));
1046        }
1047      }
1048    }
1049    catch (RuntimeException JavaDoc e)
1050    {
1051      String JavaDoc msg = Translate.get("loadbalancer.request.failed",
1052          new String JavaDoc[]{request.getSqlShortForm(vdb.getSqlShortFormLength()),
1053              e.getMessage()});
1054      logger.fatal(msg, e);
1055      endUserLogger.fatal(msg);
1056      throw new SQLException JavaDoc(msg);
1057    }
1058  }
1059
1060  /**
1061   * Execute a request that return multiple results on the selected backend.
1062   *
1063   * @param request the request to execute
1064   * @param backend the backend that will execute the request
1065   * @param metadataCache MetadataCache (null if none)
1066   * @return an <code>ExecuteResult</code> object
1067   * @throws SQLException if an error occurs
1068   */

1069  private ExecuteResult executeStatementExecuteOnBackend(
1070      AbstractRequest request, DatabaseBackend backend,
1071      MetadataCache metadataCache) throws SQLException JavaDoc,
1072      UnreachableBackendException
1073  {
1074    // Ok, we have a backend, let's execute the request
1075
AbstractConnectionManager cm = backend.getConnectionManager(request
1076        .getLogin());
1077
1078    // Sanity check
1079
if (cm == null)
1080    {
1081      String JavaDoc msg = Translate.get("loadbalancer.connectionmanager.not.found",
1082          new String JavaDoc[]{request.getLogin(), backend.getName()});
1083      logger.error(msg);
1084      throw new SQLException JavaDoc(msg);
1085    }
1086
1087    // Execute the query
1088
if (request.isAutoCommit())
1089    {
1090      // Use a connection just for this request
1091
PooledConnection c = null;
1092      try
1093      {
1094        c = cm.retrieveConnectionInAutoCommit(request);
1095      }
1096      catch (UnreachableBackendException e1)
1097      {
1098        String JavaDoc msg = Translate.get(
1099            "loadbalancer.backend.disabling.unreachable", backend.getName());
1100        logger.error(msg);
1101        endUserLogger.error(msg);
1102        disableBackend(backend, true);
1103        throw new UnreachableBackendException(Translate.get(
1104            "loadbalancer.backend.unreacheable", backend.getName()));
1105      }
1106
1107      // Sanity check
1108
if (c == null)
1109        throw new UnreachableBackendException(Translate.get(
1110            "loadbalancer.backend.no.connection", backend.getName()));
1111
1112      // Execute Query
1113
ExecuteResult rs = null;
1114      try
1115      {
1116        rs = AbstractLoadBalancer.executeStatementExecuteOnBackend(request,
1117            backend, null, c.getConnection(), metadataCache);
1118      }
1119      catch (Exception JavaDoc e)
1120      {
1121        throw new SQLException JavaDoc(Translate.get(
1122            "loadbalancer.request.failed.on.backend", new String JavaDoc[]{
1123                request.getSqlShortForm(vdb.getSqlShortFormLength()),
1124                backend.getName(), e.getMessage()}));
1125      }
1126      finally
1127      {
1128        cm.releaseConnectionInAutoCommit(request, c);
1129      }
1130      if (logger.isDebugEnabled())
1131        logger.debug(Translate.get("loadbalancer.request.on", new String JavaDoc[]{
1132            String.valueOf(request.getId()), backend.getName()}));
1133      return rs;
1134    }
1135    else
1136    { // Inside a transaction
1137
Connection JavaDoc c;
1138      long tid = request.getTransactionId();
1139
1140      try
1141      {
1142        c = backend
1143            .getConnectionForTransactionAndLazyBeginIfNeeded(request, cm);
1144      }
1145      catch (UnreachableBackendException e1)
1146      {
1147        String JavaDoc msg = Translate.get(
1148            "loadbalancer.backend.disabling.unreachable", backend.getName());
1149        logger.error(msg);
1150        endUserLogger.error(msg);
1151        disableBackend(backend, true);
1152        throw new SQLException JavaDoc(Translate.get(
1153            "loadbalancer.backend.unreacheable", backend.getName()));
1154      }
1155      catch (NoTransactionStartWhenDisablingException e)
1156      {
1157        String JavaDoc msg = Translate.get("loadbalancer.backend.is.disabling",
1158            new String JavaDoc[]{request.getSqlShortForm(vdb.getSqlShortFormLength()),
1159                backend.getName()});
1160        logger.error(msg);
1161        throw new SQLException JavaDoc(msg);
1162      }
1163
1164      // Sanity check
1165
if (c == null)
1166        throw new SQLException JavaDoc(Translate.get(
1167            "loadbalancer.unable.retrieve.connection", new String JavaDoc[]{
1168                String.valueOf(tid), backend.getName()}));
1169
1170      // Execute Query
1171
ExecuteResult rs;
1172      try
1173      {
1174        rs = AbstractLoadBalancer.executeStatementExecuteOnBackend(request,
1175            backend, null, c, metadataCache);
1176      }
1177      catch (Exception JavaDoc e)
1178      {
1179        throw new SQLException JavaDoc(Translate.get(
1180            "loadbalancer.request.failed.on.backend", new String JavaDoc[]{
1181                request.getSqlShortForm(vdb.getSqlShortFormLength()),
1182                backend.getName(), e.getMessage()}));
1183      }
1184      if (logger.isDebugEnabled())
1185        logger.debug(Translate.get("loadbalancer.execute.transaction.on",
1186            new String JavaDoc[]{String.valueOf(tid), String.valueOf(request.getId()),
1187                backend.getName()}));
1188      return rs;
1189    }
1190  }
1191
1192  /**
1193   * Execute a stored procedure on the selected backend.
1194   *
1195   * @param proc the stored procedure to execute
1196   * @param backend the backend that will execute the request
1197   * @param metadataCache MetadataCache (null if none)
1198   * @return the ControllerResultSet
1199   * @throws SQLException if an error occurs
1200   */

1201  private ControllerResultSet executeCallableStatementExecuteQueryOnBackend(
1202      StoredProcedure proc, DatabaseBackend backend, MetadataCache metadataCache)
1203      throws SQLException JavaDoc, UnreachableBackendException
1204  {
1205    // Ok, we have a backend, let's execute the request
1206
AbstractConnectionManager cm = backend
1207        .getConnectionManager(proc.getLogin());
1208
1209    // Sanity check
1210
if (cm == null)
1211    {
1212      String JavaDoc msg = Translate.get("loadbalancer.connectionmanager.not.found",
1213          new String JavaDoc[]{proc.getLogin(), backend.getName()});
1214      logger.error(msg);
1215      throw new SQLException JavaDoc(msg);
1216    }
1217
1218    // Execute the query
1219
if (proc.isAutoCommit())
1220    {
1221      // Use a connection just for this request
1222
PooledConnection c = null;
1223      try
1224      {
1225        c = cm.retrieveConnectionInAutoCommit(proc);
1226      }
1227      catch (UnreachableBackendException e1)
1228      {
1229        String JavaDoc msg = Translate.get(
1230            "loadbalancer.backend.disabling.unreachable", backend.getName());
1231        logger.error(msg);
1232        endUserLogger.error(msg);
1233        disableBackend(backend, true);
1234        throw new UnreachableBackendException(Translate.get(
1235            "loadbalancer.backend.unreacheable", backend.getName()));
1236      }
1237
1238      // Sanity check
1239
if (c == null)
1240        throw new UnreachableBackendException(Translate.get(
1241            "loadbalancer.backend.no.connection", backend.getName()));
1242
1243      // Execute Query
1244
ControllerResultSet rs = null;
1245      try
1246      {
1247        rs = AbstractLoadBalancer
1248            .executeCallableStatementExecuteQueryOnBackend(proc, backend, null,
1249                c.getConnection(), metadataCache);
1250      }
1251      catch (Exception JavaDoc e)
1252      {
1253        throw new SQLException JavaDoc(Translate.get(
1254            "loadbalancer.storedprocedure.failed.on.backend", new String JavaDoc[]{
1255                proc.getSqlShortForm(vdb.getSqlShortFormLength()),
1256                backend.getName(), e.getMessage()}));
1257      }
1258      finally
1259      {
1260        cm.releaseConnectionInAutoCommit(proc, c);
1261      }
1262      if (logger.isDebugEnabled())
1263        logger.debug(Translate.get("loadbalancer.storedprocedure.on",
1264            new String JavaDoc[]{String.valueOf(proc.getId()), backend.getName()}));
1265      return rs;
1266    }
1267    else
1268    { // Inside a transaction
1269
Connection JavaDoc c;
1270      long tid = proc.getTransactionId();
1271
1272      try
1273      {
1274        c = backend.getConnectionForTransactionAndLazyBeginIfNeeded(proc, cm);
1275      }
1276      catch (UnreachableBackendException e1)
1277      {
1278        String JavaDoc msg = Translate.get(
1279            "loadbalancer.backend.disabling.unreachable", backend.getName());
1280        logger.error(msg);
1281        endUserLogger.error(msg);
1282        disableBackend(backend, true);
1283        throw new SQLException JavaDoc(Translate.get(
1284            "loadbalancer.backend.unreacheable", backend.getName()));
1285      }
1286      catch (NoTransactionStartWhenDisablingException e)
1287      {
1288        String JavaDoc msg = Translate.get("loadbalancer.backend.is.disabling",
1289            new String JavaDoc[]{proc.getSqlShortForm(vdb.getSqlShortFormLength()),
1290                backend.getName()});
1291        logger.error(msg);
1292        throw new SQLException JavaDoc(msg);
1293      }
1294
1295      // Sanity check
1296
if (c == null)
1297        throw new SQLException JavaDoc(Translate.get(
1298            "loadbalancer.unable.retrieve.connection", new String JavaDoc[]{
1299                String.valueOf(tid), backend.getName()}));
1300
1301      // Execute Query
1302
ControllerResultSet rs;
1303      try
1304      {
1305        rs = AbstractLoadBalancer
1306            .executeCallableStatementExecuteQueryOnBackend(proc, backend, null,
1307                c, metadataCache);
1308      }
1309      catch (Exception JavaDoc e)
1310      {
1311        throw new SQLException JavaDoc(Translate.get(
1312            "loadbalancer.storedprocedure.failed.on.backend", new String JavaDoc[]{
1313                proc.getSqlShortForm(vdb.getSqlShortFormLength()),
1314                backend.getName(), e.getMessage()}));
1315      }
1316      if (logger.isDebugEnabled())
1317        logger.debug(Translate.get("loadbalancer.execute.transaction.on",
1318            new String JavaDoc[]{String.valueOf(tid), String.valueOf(proc.getId()),
1319                backend.getName()}));
1320      return rs;
1321    }
1322  }
1323
1324  /**
1325   * Execute a stored procedure on the selected backend.
1326   *
1327   * @param proc the stored procedure to execute
1328   * @param backend the backend that will execute the request
1329   * @return the ResultSet
1330   * @throws SQLException if an error occurs
1331   */

1332  private ExecuteUpdateResult executeCallableStatementExecuteUpdateOnBackend(
1333      StoredProcedure proc, DatabaseBackend backend) throws SQLException JavaDoc,
1334      UnreachableBackendException
1335  {
1336    // Ok, we have a backend, let's execute the request
1337
AbstractConnectionManager cm = backend
1338        .getConnectionManager(proc.getLogin());
1339
1340    // Sanity check
1341
if (cm == null)
1342    {
1343      String JavaDoc msg = Translate.get("loadbalancer.connectionmanager.not.found",
1344          new String JavaDoc[]{proc.getLogin(), backend.getName()});
1345      logger.error(msg);
1346      throw new SQLException JavaDoc(msg);
1347    }
1348
1349    // Execute the query
1350
if (proc.isAutoCommit())
1351    {
1352      // Use a connection just for this request
1353
PooledConnection c = null;
1354      try
1355      {
1356        c = cm.retrieveConnectionInAutoCommit(proc);
1357      }
1358      catch (UnreachableBackendException e1)
1359      {
1360        String JavaDoc msg = Translate.get(
1361            "loadbalancer.backend.disabling.unreachable", backend.getName());
1362        logger.error(msg);
1363        endUserLogger.error(msg);
1364        disableBackend(backend, true);
1365        throw new UnreachableBackendException(Translate.get(
1366            "loadbalancer.backend.unreacheable", backend.getName()));
1367      }
1368
1369      // Sanity check
1370
if (c == null)
1371        throw new UnreachableBackendException(Translate.get(
1372            "loadbalancer.backend.no.connection", backend.getName()));
1373
1374      // Execute Query
1375
ExecuteUpdateResult result;
1376      try
1377      {
1378        result = AbstractLoadBalancer
1379            .executeCallableStatementExecuteUpdateOnBackend(proc, backend,
1380                null, c.getConnection());
1381
1382        // Warning! No way to detect if schema has been modified unless
1383
// we ask the backend again using DatabaseMetaData.getTables().
1384
}
1385      catch (Exception JavaDoc e)
1386      {
1387        throw new SQLException JavaDoc(Translate.get(
1388            "loadbalancer.storedprocedure.failed.on.backend", new String JavaDoc[]{
1389                proc.getSqlShortForm(vdb.getSqlShortFormLength()),
1390                backend.getName(), e.getMessage()}));
1391      }
1392      finally
1393      {
1394        cm.releaseConnectionInAutoCommit(proc, c);
1395      }
1396      if (logger.isDebugEnabled())
1397        logger.debug(Translate.get("loadbalancer.storedprocedure.on",
1398            new String JavaDoc[]{String.valueOf(proc.getId()), backend.getName()}));
1399      return result;
1400    }
1401    else
1402    { // Inside a transaction
1403
Connection JavaDoc c;
1404      long tid = proc.getTransactionId();
1405
1406      try
1407      {
1408        c = backend.getConnectionForTransactionAndLazyBeginIfNeeded(proc, cm);
1409      }
1410      catch (UnreachableBackendException e1)
1411      {
1412        String JavaDoc msg = Translate.get(
1413            "loadbalancer.backend.disabling.unreachable", backend.getName());
1414        logger.error(msg);
1415        endUserLogger.error(msg);
1416        disableBackend(backend, true);
1417        throw new SQLException JavaDoc(Translate.get(
1418            "loadbalancer.backend.unreacheable", backend.getName()));
1419      }
1420      catch (NoTransactionStartWhenDisablingException e)
1421      {
1422        String JavaDoc msg = Translate.get("loadbalancer.backend.is.disabling",
1423            new String JavaDoc[]{proc.getSqlShortForm(vdb.getSqlShortFormLength()),
1424                backend.getName()});
1425        logger.error(msg);
1426        throw new SQLException JavaDoc(msg);
1427      }
1428
1429      // Sanity check
1430
if (c == null)
1431        throw new SQLException JavaDoc(Translate.get(
1432            "loadbalancer.unable.retrieve.connection", new String JavaDoc[]{
1433                String.valueOf(tid), backend.getName()}));
1434
1435      // Execute Query
1436
ExecuteUpdateResult result;
1437      try
1438      {
1439        result = AbstractLoadBalancer
1440            .executeCallableStatementExecuteUpdateOnBackend(proc, backend,
1441                null, c);
1442
1443        // Warning! No way to detect if schema has been modified unless
1444
// we ask the backend again using DatabaseMetaData.getTables().
1445
}
1446      catch (Exception JavaDoc e)
1447      {
1448        throw new SQLException JavaDoc(Translate.get(
1449            "loadbalancer.storedprocedure.failed.on.backend", new String JavaDoc[]{
1450                proc.getSqlShortForm(vdb.getSqlShortFormLength()),
1451                backend.getName(), e.getMessage()}));
1452      }
1453      if (logger.isDebugEnabled())
1454        logger.debug(Translate.get("loadbalancer.execute.transaction.on",
1455            new String JavaDoc[]{String.valueOf(tid), String.valueOf(proc.getId()),
1456                backend.getName()}));
1457      return result;
1458    }
1459  }
1460
1461  /**
1462   * Execute a stored procedure that return multiple results on the selected
1463   * backend.
1464   *
1465   * @param proc the stored procedure to execute
1466   * @param backend the backend that will execute the request
1467   * @param metadataCache MetadataCache (null if none)
1468   * @return an <code>ExecuteResult</code> object
1469   * @throws SQLException if an error occurs
1470   */

1471  private ExecuteResult executeCallableStatementExecuteOnBackend(
1472      StoredProcedure proc, DatabaseBackend backend, MetadataCache metadataCache)
1473      throws SQLException JavaDoc, UnreachableBackendException
1474  {
1475    // Ok, we have a backend, let's execute the request
1476
AbstractConnectionManager cm = backend
1477        .getConnectionManager(proc.getLogin());
1478
1479    // Sanity check
1480
if (cm == null)
1481    {
1482      String JavaDoc msg = Translate.get("loadbalancer.connectionmanager.not.found",
1483          new String JavaDoc[]{proc.getLogin(), backend.getName()});
1484      logger.error(msg);
1485      throw new SQLException JavaDoc(msg);
1486    }
1487
1488    // Execute the query
1489
if (proc.isAutoCommit())
1490    {
1491      // Use a connection just for this request
1492
PooledConnection c = null;
1493      try
1494      {
1495        c = cm.retrieveConnectionInAutoCommit(proc);
1496      }
1497      catch (UnreachableBackendException e1)
1498      {
1499        String JavaDoc msg = Translate.get(
1500            "loadbalancer.backend.disabling.unreachable", backend.getName());
1501        logger.error(msg);
1502        endUserLogger.error(msg);
1503        disableBackend(backend, true);
1504        throw new UnreachableBackendException(Translate.get(
1505            "loadbalancer.backend.unreacheable", backend.getName()));
1506      }
1507
1508      // Sanity check
1509
if (c == null)
1510        throw new UnreachableBackendException(Translate.get(
1511            "loadbalancer.backend.no.connection", backend.getName()));
1512
1513      // Execute Query
1514
ExecuteResult rs = null;
1515      try
1516      {
1517        rs = AbstractLoadBalancer.executeCallableStatementExecuteOnBackend(
1518            proc, backend, null, c.getConnection(), metadataCache);
1519      }
1520      catch (Exception JavaDoc e)
1521      {
1522        throw new SQLException JavaDoc(Translate.get(
1523            "loadbalancer.storedprocedure.failed.on.backend", new String JavaDoc[]{
1524                proc.getSqlShortForm(vdb.getSqlShortFormLength()),
1525                backend.getName(), e.getMessage()}));
1526      }
1527      finally
1528      {
1529        cm.releaseConnectionInAutoCommit(proc, c);
1530      }
1531      if (logger.isDebugEnabled())
1532        logger.debug(Translate.get("loadbalancer.storedprocedure.on",
1533            new String JavaDoc[]{String.valueOf(proc.getId()), backend.getName()}));
1534      return rs;
1535    }
1536    else
1537    { // Inside a transaction
1538
Connection JavaDoc c;
1539      long tid = proc.getTransactionId();
1540
1541      try
1542      {
1543        c = backend.getConnectionForTransactionAndLazyBeginIfNeeded(proc, cm);
1544      }
1545      catch (UnreachableBackendException e1)
1546      {
1547        String JavaDoc msg = Translate.get(
1548            "loadbalancer.backend.disabling.unreachable", backend.getName());
1549        logger.error(msg);
1550        endUserLogger.error(msg);
1551        disableBackend(backend, true);
1552        throw new SQLException JavaDoc(Translate.get(
1553            "loadbalancer.backend.unreacheable", backend.getName()));
1554      }
1555      catch (NoTransactionStartWhenDisablingException e)
1556      {
1557        String JavaDoc msg = Translate.get("loadbalancer.backend.is.disabling",
1558            new String JavaDoc[]{proc.getSqlShortForm(vdb.getSqlShortFormLength()),
1559                backend.getName()});
1560        logger.error(msg);
1561        throw new SQLException JavaDoc(msg);
1562      }
1563
1564      // Sanity check
1565
if (c == null)
1566        throw new SQLException JavaDoc(Translate.get(
1567            "loadbalancer.unable.retrieve.connection", new String JavaDoc[]{
1568                String.valueOf(tid), backend.getName()}));
1569
1570      // Execute Query
1571
ExecuteResult rs;
1572      try
1573      {
1574        rs = AbstractLoadBalancer.executeCallableStatementExecuteOnBackend(
1575            proc, backend, null, c, metadataCache);
1576      }
1577      catch (Exception JavaDoc e)
1578      {
1579        throw new SQLException JavaDoc(Translate.get(
1580            "loadbalancer.storedprocedure.failed.on.backend", new String JavaDoc[]{
1581                proc.getSqlShortForm(vdb.getSqlShortFormLength()),
1582                backend.getName(), e.getMessage()}));
1583      }
1584      if (logger.isDebugEnabled())
1585        logger.debug(Translate.get("loadbalancer.execute.transaction.on",
1586            new String JavaDoc[]{String.valueOf(tid), String.valueOf(proc.getId()),
1587                backend.getName()}));
1588      return rs;
1589    }
1590  }
1591
1592  /**
1593   * @see org.continuent.sequoia.controller.loadbalancer.AbstractLoadBalancer#getPreparedStatementGetMetaData(org.continuent.sequoia.controller.requests.AbstractRequest)
1594   */

1595  public ControllerResultSet getPreparedStatementGetMetaData(
1596      AbstractRequest request) throws SQLException JavaDoc
1597  {
1598    DatabaseBackend backend = chooseBackendForReadRequest(request);
1599
1600    if (backend == null)
1601      throw new NoMoreBackendException(Translate.get(
1602          "loadbalancer.execute.no.backend.enabled", request.getId()));
1603
1604    // Ok, we have a backend, let's execute the request
1605
AbstractConnectionManager cm = backend.getConnectionManager(request
1606        .getLogin());
1607
1608    // Sanity check
1609
if (cm == null)
1610    {
1611      String JavaDoc msg = Translate.get("loadbalancer.connectionmanager.not.found",
1612          new String JavaDoc[]{request.getLogin(), backend.getName()});
1613      logger.error(msg);
1614      throw new SQLException JavaDoc(msg);
1615    }
1616
1617    // Execute the query
1618
if (request.isAutoCommit())
1619    {
1620      ControllerResultSet rs = null;
1621      boolean badConnection;
1622      do
1623      {
1624        badConnection = false;
1625        // Use a connection just for this request
1626
PooledConnection c = null;
1627        try
1628        {
1629          c = cm.retrieveConnectionInAutoCommit(request);
1630        }
1631        catch (UnreachableBackendException e1)
1632        {
1633          String JavaDoc msg = Translate.get(
1634              "loadbalancer.backend.disabling.unreachable", backend.getName());
1635          logger.error(msg);
1636          endUserLogger.error(msg);
1637          disableBackend(backend, true);
1638          // Retry on a different backend
1639
return getPreparedStatementGetMetaData(request);
1640        }
1641
1642        // Sanity check
1643
if (c == null)
1644          throw new SQLException JavaDoc(Translate.get(
1645              "loadbalancer.backend.no.connection", backend.getName()));
1646
1647        // Execute Query
1648
try
1649        {
1650          rs = preparedStatementGetMetaDataOnBackend(
1651              request.getSqlOrTemplate(), backend, c.getConnection());
1652          cm.releaseConnectionInAutoCommit(request, c);
1653        }
1654        catch (SQLException JavaDoc e)
1655        {
1656          cm.releaseConnectionInAutoCommit(request, c);
1657          throw SQLExceptionFactory.getSQLException(e, Translate.get(
1658              "loadbalancer.request.failed.on.backend", new String JavaDoc[]{
1659                  request.getSqlShortForm(vdb.getSqlShortFormLength()),
1660                  backend.getName(), e.getMessage()}));
1661        }
1662        catch (BadConnectionException e)
1663        { // Get rid of the bad connection
1664
cm.deleteConnection(c);
1665          badConnection = true;
1666        }
1667        catch (Throwable JavaDoc e)
1668        {
1669          cm.releaseConnectionInAutoCommit(request, c);
1670          throw new SQLException JavaDoc(Translate.get(
1671              "loadbalancer.request.failed.on.backend", new String JavaDoc[]{
1672                  request.getSqlShortForm(vdb.getSqlShortFormLength()),
1673                  backend.getName(), e.getMessage()}));
1674        }
1675      }
1676      while (badConnection);
1677      if (logger.isDebugEnabled())
1678        logger.debug(Translate.get("loadbalancer.execute.on", new String JavaDoc[]{
1679            String.valueOf(request.getId()), backend.getName()}));
1680      return rs;
1681    }
1682    else
1683    { // Inside a transaction
1684
Connection JavaDoc c;
1685      long tid = request.getTransactionId();
1686
1687      try
1688      {
1689        c = backend
1690            .getConnectionForTransactionAndLazyBeginIfNeeded(request, cm);
1691      }
1692      catch (UnreachableBackendException e1)
1693      {
1694        String JavaDoc msg = Translate.get(
1695            "loadbalancer.backend.disabling.unreachable", backend.getName());
1696        logger.error(msg);
1697        endUserLogger.error(msg);
1698        disableBackend(backend, true);
1699        throw new SQLException JavaDoc(Translate.get(
1700            "loadbalancer.backend.unreacheable", backend.getName()));
1701      }
1702      catch (NoTransactionStartWhenDisablingException e)
1703      {
1704        String JavaDoc msg = Translate.get("loadbalancer.backend.is.disabling",
1705            new String JavaDoc[]{request.getSqlShortForm(vdb.getSqlShortFormLength()),
1706                backend.getName()});
1707        logger.error(msg);
1708        throw new SQLException JavaDoc(msg);
1709      }
1710
1711      // Sanity check
1712
if (c == null)
1713        throw new SQLException JavaDoc(Translate.get(
1714            "loadbalancer.unable.retrieve.connection", new String JavaDoc[]{
1715                String.valueOf(tid), backend.getName()}));
1716
1717      // Execute Query
1718
ControllerResultSet rs = null;
1719      try
1720      {
1721        rs = preparedStatementGetMetaDataOnBackend(request.getSqlOrTemplate(),
1722            backend, c);
1723      }
1724      catch (SQLException JavaDoc e)
1725      {
1726        throw e;
1727      }
1728      catch (BadConnectionException e)
1729      { // Connection failed, so did the transaction
1730
// Disable the backend.
1731
cm.deleteConnection(tid);
1732        String JavaDoc msg = Translate.get(
1733            "loadbalancer.backend.disabling.connection.failure", backend
1734                .getName());
1735        logger.error(msg);
1736        endUserLogger.error(msg);
1737        disableBackend(backend, true);
1738        throw new SQLException JavaDoc(msg);
1739      }
1740      catch (Throwable JavaDoc e)
1741      {
1742        throw new SQLException JavaDoc(Translate.get(
1743            "loadbalancer.request.failed.on.backend", new String JavaDoc[]{
1744                request.getSqlShortForm(vdb.getSqlShortFormLength()),
1745                backend.getName(), e.getMessage()}));
1746      }
1747      if (logger.isDebugEnabled())
1748        logger.debug(Translate.get("loadbalancer.execute.transaction.on",
1749            new String JavaDoc[]{String.valueOf(tid), String.valueOf(request.getId()),
1750                backend.getName()}));
1751      return rs;
1752    }
1753  }
1754
1755  //
1756
// Transaction Management
1757
//
1758

1759  /**
1760   * @see org.continuent.sequoia.controller.loadbalancer.AbstractLoadBalancer#abort(org.continuent.sequoia.controller.requestmanager.TransactionMetaData)
1761   */

1762  public void abort(TransactionMetaData tm) throws SQLException JavaDoc
1763  {
1764    rollback(tm);
1765  }
1766
1767  /**
1768   * @see org.continuent.sequoia.controller.loadbalancer.AbstractLoadBalancer#begin(org.continuent.sequoia.controller.requestmanager.TransactionMetaData)
1769   */

1770  public void begin(TransactionMetaData tm) throws SQLException JavaDoc
1771  {
1772    Long JavaDoc lTid = new Long JavaDoc(tm.getTransactionId());
1773    if (backendPerTransactionId.containsKey(lTid))
1774      throw new SQLException JavaDoc(Translate.get(
1775          "loadbalancer.transaction.already.started", lTid.toString()));
1776
1777    DatabaseBackend backend = chooseBackendForReadRequest(new UnknownReadRequest(
1778        "begin", false, 0, "\n"));
1779    backendPerTransactionId.put(lTid, backend);
1780    backend.startTransaction(lTid);
1781  }
1782
1783  /**
1784   * @see org.continuent.sequoia.controller.loadbalancer.AbstractLoadBalancer#commit(org.continuent.sequoia.controller.requestmanager.TransactionMetaData)
1785   */

1786  public void commit(TransactionMetaData tm) throws SQLException JavaDoc
1787  {
1788    long tid = tm.getTransactionId();
1789    Long JavaDoc lTid = new Long JavaDoc(tid);
1790    DatabaseBackend db = (DatabaseBackend) backendPerTransactionId.remove(lTid);
1791
1792    AbstractConnectionManager cm = db.getConnectionManager(tm.getLogin());
1793    PooledConnection pc = cm.retrieveConnectionForTransaction(tid);
1794
1795    long logId = 0;
1796    // Log the request
1797
if (recoveryLog != null)
1798      logId = recoveryLog.logCommit(tm);
1799
1800    // Sanity check
1801
if (pc == null)
1802    { // Bad connection
1803
db.stopTransaction(lTid);
1804
1805      throw new SQLException JavaDoc(Translate.get(
1806          "loadbalancer.unable.retrieve.connection", new String JavaDoc[]{
1807              String.valueOf(tid), db.getName()}));
1808    }
1809
1810    // Execute Query
1811
try
1812    {
1813      Connection JavaDoc c = pc.getConnection();
1814      c.commit();
1815      c.setAutoCommit(true);
1816    }
1817    catch (Exception JavaDoc e)
1818    {
1819      // Notify failure in recovery log
1820
if (recoveryLog != null)
1821        recoveryLog.logRequestCompletion(logId, false, 0);
1822
1823      String JavaDoc msg = Translate.get("loadbalancer.commit.failed", new String JavaDoc[]{
1824          String.valueOf(tid), db.getName(), e.getMessage()});
1825      logger.error(msg);
1826      throw new SQLException JavaDoc(msg);
1827    }
1828    finally
1829    {
1830      cm.releaseConnectionForTransaction(tid);
1831      db.stopTransaction(lTid);
1832    }
1833  }
1834
1835  /**
1836   * @see org.continuent.sequoia.controller.loadbalancer.AbstractLoadBalancer#rollback(org.continuent.sequoia.controller.requestmanager.TransactionMetaData)
1837   */

1838  public void rollback(TransactionMetaData tm) throws SQLException JavaDoc
1839  {
1840    long tid = tm.getTransactionId();
1841    Long JavaDoc lTid = new Long JavaDoc(tid);
1842    DatabaseBackend db = (DatabaseBackend) backendPerTransactionId.remove(lTid);
1843
1844    AbstractConnectionManager cm = db.getConnectionManager(tm.getLogin());
1845    PooledConnection pc = cm.retrieveConnectionForTransaction(tid);
1846
1847    long logId = 0;
1848    // Log the request
1849
if (recoveryLog != null)
1850      logId = recoveryLog.logRollback(tm);
1851
1852    // Sanity check
1853
if (pc == null)
1854    { // Bad connection
1855
db.stopTransaction(lTid);
1856
1857      throw new SQLException JavaDoc(Translate.get(
1858          "loadbalancer.unable.retrieve.connection", new String JavaDoc[]{
1859              String.valueOf(tid), db.getName()}));
1860    }
1861
1862    // Execute Query
1863
try
1864    {
1865      Connection JavaDoc c = pc.getConnection();
1866      c.rollback();
1867
1868      c.setAutoCommit(true);
1869    }
1870    catch (Exception JavaDoc e)
1871    {
1872      // Notify failure in recovery log
1873
if (recoveryLog != null)
1874        recoveryLog.logRequestCompletion(logId, false, 0);
1875
1876      String JavaDoc msg = Translate.get("loadbalancer.rollback.failed", new String JavaDoc[]{
1877          String.valueOf(tid), db.getName(), e.getMessage()});
1878      logger.error(msg);
1879      throw new SQLException JavaDoc(msg);
1880    }
1881    finally
1882    {
1883      cm.releaseConnectionForTransaction(tid);
1884      db.stopTransaction(lTid);
1885    }
1886  }
1887
1888  /**
1889   * Rollback a transaction to a savepoint
1890   *
1891   * @param tm The transaction marker metadata
1892   * @param savepointName The name of the savepoint
1893   * @throws SQLException if an error occurs
1894   */

1895  public void rollbackToSavepoint(TransactionMetaData tm, String JavaDoc savepointName)
1896      throws SQLException JavaDoc
1897  {
1898    long tid = tm.getTransactionId();
1899    Long JavaDoc lTid = new Long JavaDoc(tid);
1900    DatabaseBackend db = (DatabaseBackend) backendPerTransactionId.remove(lTid);
1901
1902    AbstractConnectionManager cm = db.getConnectionManager(tm.getLogin());
1903    PooledConnection c = cm.retrieveConnectionForTransaction(tid);
1904
1905    long logId = 0;
1906    // Log the request
1907
if (recoveryLog != null)
1908      logId = recoveryLog.logRollbackToSavepoint(tm, savepointName);
1909
1910    // Sanity check
1911
if (c == null)
1912    { // Bad connection
1913
db.stopTransaction(lTid);
1914
1915      throw new SQLException JavaDoc(Translate.get(
1916          "loadbalancer.unable.retrieve.connection", new String JavaDoc[]{
1917              String.valueOf(tid), db.getName()}));
1918    }
1919
1920    // Retrieve savepoint
1921
Savepoint JavaDoc savepoint = db.getSavepoint(lTid, savepointName);
1922    if (savepoint == null)
1923    {
1924      throw new SQLException JavaDoc(Translate.get(
1925          "loadbalancer.unable.retrieve.savepoint", new String JavaDoc[]{savepointName,
1926              String.valueOf(tid), db.getName()}));
1927    }
1928
1929    // Execute Query
1930
try
1931    {
1932      c.getConnection().rollback(savepoint);
1933    }
1934    catch (Exception JavaDoc e)
1935    {
1936      // Notify failure in recovery log
1937
if (recoveryLog != null)
1938        recoveryLog.logRequestCompletion(logId, false, 0);
1939
1940      String JavaDoc msg = Translate.get("loadbalancer.rollbacksavepoint.failed",
1941          new String JavaDoc[]{savepointName, String.valueOf(tid), db.getName(),
1942              e.getMessage()});
1943      logger.error(msg);
1944      throw new SQLException JavaDoc(msg);
1945    }
1946  }
1947
1948  /**
1949   * Release a savepoint from a transaction
1950   *
1951   * @param tm The transaction marker metadata
1952   * @param savepointName The name of the savepoint ro release
1953   * @throws SQLException if an error occurs
1954   */

1955  public void releaseSavepoint(TransactionMetaData tm, String JavaDoc savepointName)
1956      throws SQLException JavaDoc
1957  {
1958    long tid = tm.getTransactionId();
1959    Long JavaDoc lTid = new Long JavaDoc(tid);
1960
1961    DatabaseBackend db = (DatabaseBackend) backendPerTransactionId.get(lTid);
1962    AbstractConnectionManager cm = db.getConnectionManager(tm.getLogin());
1963    PooledConnection c = cm.retrieveConnectionForTransaction(tid);
1964
1965    long logId = 0;
1966    // Log the request
1967
if (recoveryLog != null)
1968      logId = recoveryLog.logReleaseSavepoint(tm, savepointName);
1969
1970    // Sanity check
1971
if (c == null)
1972    { // Bad connection
1973
db.stopTransaction(lTid);
1974
1975      throw new SQLException JavaDoc(Translate.get(
1976          "loadbalancer.unable.retrieve.connection", new String JavaDoc[]{
1977              String.valueOf(tid), db.getName()}));
1978    }
1979
1980    // Retrieve savepoint
1981
Savepoint JavaDoc savepoint = db.getSavepoint(lTid, savepointName);
1982    if (savepoint == null)
1983    {
1984      throw new SQLException JavaDoc(Translate.get(
1985          "loadbalancer.unable.retrieve.savepoint", new String JavaDoc[]{
1986              String.valueOf(tid), savepointName, db.getName()}));
1987    }
1988
1989    // Execute Query
1990
try
1991    {
1992      c.getConnection().releaseSavepoint(savepoint);
1993    }
1994    catch (Exception JavaDoc e)
1995    {
1996      // Notify failure in recovery log
1997
if (recoveryLog != null)
1998        recoveryLog.logRequestCompletion(logId, false, 0);
1999
2000      String JavaDoc msg = Translate.get("loadbalancer.releasesavepoint.failed",
2001          new String JavaDoc[]{savepointName, String.valueOf(tid), db.getName(),
2002              e.getMessage()});
2003      logger.error(msg);
2004      throw new SQLException JavaDoc(msg);
2005    }
2006    finally
2007    {
2008      db.removeSavepoint(lTid, savepoint);
2009    }
2010  }
2011
2012  /**
2013   * Set a savepoint to a transaction.
2014   *
2015   * @param tm The transaction marker metadata
2016   * @param savepointName The name of the new savepoint
2017   * @throws SQLException if an error occurs
2018   */

2019  public void setSavepoint(TransactionMetaData tm, String JavaDoc savepointName)
2020      throws SQLException JavaDoc
2021  {
2022    long tid = tm.getTransactionId();
2023    Long JavaDoc lTid = new Long JavaDoc(tid);
2024
2025    DatabaseBackend db = (DatabaseBackend) backendPerTransactionId.get(lTid);
2026    AbstractConnectionManager cm = db.getConnectionManager(tm.getLogin());
2027    PooledConnection c = cm.retrieveConnectionForTransaction(tid);
2028
2029    long logId = 0;
2030    // Log the request
2031
if (recoveryLog != null)
2032      logId = recoveryLog.logSetSavepoint(tm, savepointName);
2033
2034    // Sanity check
2035
if (c == null)
2036    { // Bad connection
2037
db.stopTransaction(lTid);
2038
2039      throw new SQLException JavaDoc(Translate.get(
2040          "loadbalancer.unable.retrieve.connection", new String JavaDoc[]{
2041              String.valueOf(tid), db.getName()}));
2042    }
2043
2044    // Execute Query
2045
Savepoint JavaDoc savepoint = null;
2046    try
2047    {
2048      savepoint = c.getConnection().setSavepoint(savepointName);
2049    }
2050    catch (Exception JavaDoc e)
2051    {
2052      // Notify failure in recovery log
2053
if (recoveryLog != null)
2054        recoveryLog.logRequestCompletion(logId, false, 0);
2055
2056      String JavaDoc msg = Translate.get("loadbalancer.setsavepoint.failed",
2057          new String JavaDoc[]{savepointName, String.valueOf(tid), db.getName(),
2058              e.getMessage()});
2059      logger.error(msg);
2060      throw new SQLException JavaDoc(msg);
2061    }
2062    finally
2063    {
2064      if (savepoint != null)
2065        db.addSavepoint(lTid, savepoint);
2066    }
2067  }
2068
2069  /**
2070   * @see org.continuent.sequoia.controller.loadbalancer.AbstractLoadBalancer#closePersistentConnection(java.lang.String,
2071   * long)
2072   */

2073  public void closePersistentConnection(String JavaDoc login,
2074      long persistentConnectionId) throws SQLException JavaDoc
2075  {
2076    try
2077    {
2078      vdb.acquireReadLockBackendLists();
2079    }
2080    catch (InterruptedException JavaDoc e)
2081    {
2082      String JavaDoc msg = Translate.get(
2083          "loadbalancer.backendlist.acquire.readlock.failed", e);
2084      logger.error(msg);
2085    }
2086    int size = vdb.getBackends().size();
2087    List JavaDoc backends = vdb.getBackends();
2088    for (int i = 0; i < size; i++)
2089    {
2090      DatabaseBackend backend = (DatabaseBackend) backends.get(i);
2091      AbstractConnectionManager cm = backend.getConnectionManager(login);
2092      if (cm != null)
2093      {
2094        cm.releasePersistentConnectionInAutoCommit(persistentConnectionId);
2095        backend.removePersistentConnection(persistentConnectionId);
2096      }
2097    }
2098    vdb.releaseReadLockBackendLists();
2099  }
2100
2101  /**
2102   * @see org.continuent.sequoia.controller.loadbalancer.AbstractLoadBalancer#openPersistentConnection(String,
2103   * long)
2104   */

2105  public void openPersistentConnection(String JavaDoc login, long persistentConnectionId)
2106      throws SQLException JavaDoc
2107  {
2108    // Fake request to call the method that creates persistent connections
2109
AbstractRequest request = new UnknownReadRequest("", false, 0, "");
2110    request.setLogin(login);
2111    request.setPersistentConnection(true);
2112    request.setPersistentConnectionId(persistentConnectionId);
2113
2114    try
2115    {
2116      vdb.acquireReadLockBackendLists();
2117    }
2118    catch (InterruptedException JavaDoc e)
2119    {
2120      String JavaDoc msg = Translate.get(
2121          "loadbalancer.backendlist.acquire.readlock.failed", e);
2122      logger.error(msg);
2123    }
2124    int size = vdb.getBackends().size();
2125    List JavaDoc backends = vdb.getBackends();
2126    for (int i = 0; i < size; i++)
2127    {
2128      DatabaseBackend backend = (DatabaseBackend) backends.get(i);
2129      AbstractConnectionManager cm = backend.getConnectionManager(login);
2130      if (cm == null)
2131      {
2132        logger.warn("Failed to open persistent connection "
2133            + persistentConnectionId + " on backend " + backend.getName());
2134        continue;
2135      }
2136      try
2137      {
2138        // Create the persistent connection
2139
PooledConnection c = cm.retrieveConnectionInAutoCommit(request);
2140        backend.addPersistentConnection(request.getPersistentConnectionId(), c);
2141      }
2142      catch (UnreachableBackendException e)
2143      {
2144        logger.warn("Failed to open persistent connection "
2145            + persistentConnectionId + " on backend " + backend.getName(), e);
2146      }
2147    }
2148    vdb.releaseReadLockBackendLists();
2149  }
2150
2151  /**
2152   * Enables a backend that was previously disabled. Asks the corresponding
2153   * connection manager to initialize the connections if needed.
2154   * <p>
2155   * No sanity checks are performed by this function.
2156   *
2157   * @param db the database backend to enable
2158   * @param writeEnabled True if the backend must be enabled for writes
2159   * @throws SQLException if an error occurs
2160   */

2161  public void enableBackend(DatabaseBackend db, boolean writeEnabled)
2162      throws SQLException JavaDoc
2163  {
2164    logger.info(Translate.get("loadbalancer.backend.enabling", db.getName()));
2165    if (!db.isInitialized())
2166      db.initializeConnections();
2167    db.enableRead();
2168    if (writeEnabled)
2169      db.enableWrite();
2170    numberOfEnabledBackends++;
2171  }
2172
2173  /**
2174   * Disables a backend that was previously enabled. Asks the corresponding
2175   * connection manager to finalize the connections if needed.
2176   * <p>
2177   * No sanity checks are performed by this function.
2178   *
2179   * @param db the database backend to disable
2180   * @param forceDisable true if disabling must be forced on the backend
2181   * @throws SQLException if an error occurs
2182   */

2183  public void disableBackend(DatabaseBackend db, boolean forceDisable)
2184      throws SQLException JavaDoc
2185  {
2186    logger.info(Translate.get("loadbalancer.backend.disabling", db.getName()));
2187    numberOfEnabledBackends--;
2188    db.disable();
2189    if (db.isInitialized())
2190      db.finalizeConnections();
2191  }
2192
2193  /**
2194   * @see org.continuent.sequoia.controller.loadbalancer.AbstractLoadBalancer#getNumberOfEnabledBackends()
2195   */

2196  public int getNumberOfEnabledBackends()
2197  {
2198    return numberOfEnabledBackends;
2199  }
2200
2201  //
2202
// Debug/Monitoring
2203
//
2204

2205  /**
2206   * @see org.continuent.sequoia.controller.loadbalancer.AbstractLoadBalancer#getXmlImpl
2207   */

2208  public String JavaDoc getXmlImpl()
2209  {
2210    StringBuffer JavaDoc info = new StringBuffer JavaDoc();
2211    info.append("<" + DatabasesXmlTags.ELT_ParallelDB + ">");
2212    info.append(getParallelDBXml());
2213    info.append("</" + DatabasesXmlTags.ELT_ParallelDB + ">");
2214    return info.toString();
2215  }
2216
2217  /**
2218   * Return the XML tags of the ParallelDB load balancer implementation.
2219   *
2220   * @return content of ParallelDB xml
2221   */

2222  public abstract String JavaDoc getParallelDBXml();
2223
2224}
Popular Tags