KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > continuent > sequoia > controller > loadbalancer > tasks > StatementExecuteUpdateWithKeysTask


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-2006 Continuent, Inc.
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  * Initial developer(s): Emmanuel Cecchet.
21  * Contributor(s): Jaco Swart.
22  */

23
24 package org.continuent.sequoia.controller.loadbalancer.tasks;
25
26 import java.sql.Connection JavaDoc;
27 import java.sql.SQLException JavaDoc;
28
29 import org.continuent.sequoia.common.exceptions.NoTransactionStartWhenDisablingException;
30 import org.continuent.sequoia.common.exceptions.UnreachableBackendException;
31 import org.continuent.sequoia.common.i18n.Translate;
32 import org.continuent.sequoia.common.log.Trace;
33 import org.continuent.sequoia.controller.backend.DatabaseBackend;
34 import org.continuent.sequoia.controller.backend.result.GeneratedKeysResult;
35 import org.continuent.sequoia.controller.cache.metadata.MetadataCache;
36 import org.continuent.sequoia.controller.connection.AbstractConnectionManager;
37 import org.continuent.sequoia.controller.connection.PooledConnection;
38 import org.continuent.sequoia.controller.loadbalancer.AbstractLoadBalancer;
39 import org.continuent.sequoia.controller.loadbalancer.BackendWorkerThread;
40 import org.continuent.sequoia.controller.requests.AbstractRequest;
41 import org.continuent.sequoia.controller.requests.AbstractWriteRequest;
42
43 /**
44  * Executes a <code>AbstractWriteRequest</code> statement and return the auto
45  * generated keys.
46  *
47  * @author <a HREF="mailto:Emmanuel.Cecchet@inria.fr">Emmanuel Cecchet </a>
48  * @author <a HREF="mailto:jaco.swart@iblocks.co.uk">Jaco Swart </a>
49  * @version 1.0
50  */

51 public class StatementExecuteUpdateWithKeysTask extends AbstractTask
52 {
53   private AbstractWriteRequest request;
54   private GeneratedKeysResult result = null;
55   private MetadataCache metadataCache;
56
57   static Trace endUserLogger = Trace
58                                                  .getLogger("org.continuent.sequoia.enduser");
59
60   /**
61    * Creates a new <code>StatementExecuteUpdateTask</code>.
62    *
63    * @param nbToComplete number of threads that must succeed before returning
64    * @param totalNb total number of threads
65    * @param request an <code>AbstractWriteRequest</code>
66    * @param metadataCache the metadataCache if any or null
67    */

68   public StatementExecuteUpdateWithKeysTask(int nbToComplete, int totalNb,
69       AbstractWriteRequest request, MetadataCache metadataCache)
70   {
71     super(nbToComplete, totalNb, request.isPersistentConnection(), request
72         .getPersistentConnectionId());
73     this.request = request;
74     this.metadataCache = metadataCache;
75   }
76
77   /**
78    * Executes a write request with the given backend thread.
79    *
80    * @param backendThread the backend thread that will execute the task
81    * @throws SQLException if an error occurs
82    */

83   public void executeTask(BackendWorkerThread backendThread)
84       throws SQLException JavaDoc
85   {
86     DatabaseBackend backend = backendThread.getBackend();
87
88     try
89     {
90       if (!backend.getDriverCompliance().supportGetGeneratedKeys())
91         throw new SQLException JavaDoc(Translate.get(
92             "loadbalancer.backend.autogeneratedkeys.unsupported", backend
93                 .getName()));
94
95       AbstractConnectionManager cm = backend.getConnectionManager(request
96           .getLogin());
97       if (cm == null)
98       {
99         SQLException JavaDoc se = new SQLException JavaDoc(
100             "No Connection Manager for Virtual Login:" + request.getLogin());
101         try
102         {
103           notifyFailure(backendThread, -1, se);
104         }
105         catch (SQLException JavaDoc ignore)
106         {
107
108         }
109         throw se;
110       }
111
112       Trace logger = backendThread.getLogger();
113       if (request.isAutoCommit())
114         executeInAutoCommit(backendThread, backend, cm, logger);
115       else
116         executeInTransaction(backendThread, backend, cm, logger);
117
118       if (result == null)
119         return; // failure, already handled
120

121       int resultOnFirstBackendToSucceed = notifySuccess(backendThread, result
122           .getUpdateCount());
123       if (resultOnFirstBackendToSucceed != result.getUpdateCount())
124       {
125         String JavaDoc msg = "Disabling backend " + backend.getName()
126             + " that reports a different number of updated rows ("
127             + result.getUpdateCount() + ") than first backend to succeed ("
128             + resultOnFirstBackendToSucceed + ") for request " + request;
129         logger.error(msg);
130         // Disable this backend (it is no more in sync)
131
backendThread.getLoadBalancer().disableBackend(backend, true);
132         endUserLogger.error(Translate.get(
133             "loadbalancer.backend.disabling", backend.getName()));
134         throw new SQLException JavaDoc(msg);
135       }
136     }
137     finally
138     {
139       backend.getTaskQueues().completeWriteRequestExecution(this);
140     }
141   }
142
143   private void executeInAutoCommit(BackendWorkerThread backendThread,
144       DatabaseBackend backend, AbstractConnectionManager cm, Trace logger)
145       throws SQLException JavaDoc
146   {
147     if (!backend.canAcceptTasks(request))
148     {
149       // Backend is disabling, we do not play requests in autocommit, just
150
// notify
151
// the completion for the others
152
notifyCompletion(backendThread);
153       return;
154     }
155
156     // Use a connection just for this request
157
PooledConnection c = null;
158     try
159     {
160       c = cm.retrieveConnectionInAutoCommit(request);
161     }
162     catch (UnreachableBackendException e1)
163     {
164       SQLException JavaDoc se = new SQLException JavaDoc("Backend " + backend.getName()
165           + " is no more reachable.");
166       try
167       {
168         notifyFailure(backendThread, -1, se);
169       }
170       catch (SQLException JavaDoc ignore)
171       {
172       }
173       // Disable this backend (it is no more in sync) by killing the backend
174
// thread
175
backendThread.getLoadBalancer().disableBackend(backend, true);
176       String JavaDoc msg = Translate.get(
177           "loadbalancer.backend.disabling.unreachable", backend.getName());
178       logger.error(msg);
179       endUserLogger.error(msg);
180       throw se;
181     }
182
183     // Sanity check
184
if (c == null)
185     {
186       SQLException JavaDoc se = new SQLException JavaDoc("No more connections");
187       try
188       { // All backends failed, just ignore
189
if (!notifyFailure(backendThread, request.getTimeout() * 1000L, se))
190           return;
191       }
192       catch (SQLException JavaDoc ignore)
193       {
194       }
195       // Disable this backend (it is no more in sync) by killing the backend
196
// thread
197
backendThread.getLoadBalancer().disableBackend(backend, true);
198       String JavaDoc msg = "Request '"
199           + request.getSqlShortForm(backend.getSqlShortFormLength())
200           + "' failed on backend " + backend.getName() + " but " + getSuccess()
201           + " succeeded (" + se + ")";
202       logger.error(msg);
203       endUserLogger.error(Translate.get(
204           "loadbalancer.backend.disabling", backend.getName()));
205       throw new SQLException JavaDoc(msg);
206     }
207
208     // Execute Query
209
try
210     {
211       result = AbstractLoadBalancer
212           .executeStatementExecuteUpdateWithKeysOnBackend(request, backend,
213               backendThread, c.getConnection(), metadataCache);
214
215       backend.updateDatabaseBackendSchema(request);
216     }
217     catch (Exception JavaDoc e)
218     {
219       try
220       { // All backends failed, just ignore
221
if (!notifyFailure(backendThread, request.getTimeout() * 1000L, e))
222         {
223           result = null;
224           return;
225         }
226       }
227       catch (SQLException JavaDoc ignore)
228       {
229       }
230       // Disable this backend (it is no more in sync) by killing the backend
231
// thread
232
backendThread.getLoadBalancer().disableBackend(backend, true);
233       String JavaDoc msg = "Request '"
234           + request.getSqlShortForm(backend.getSqlShortFormLength())
235           + "' failed on backend " + backend.getName() + " but " + getSuccess()
236           + " succeeded (" + e + ")";
237       logger.error(msg);
238       endUserLogger.error(Translate.get(
239           "loadbalancer.backend.disabling", backend.getName()));
240       throw new SQLException JavaDoc(msg);
241     }
242     finally
243     {
244       cm.releaseConnectionInAutoCommit(request, c);
245     }
246   }
247
248   private void executeInTransaction(BackendWorkerThread backendThread,
249       DatabaseBackend backend, AbstractConnectionManager cm, Trace logger)
250       throws SQLException JavaDoc
251   {
252     // Re-use the connection used by this transaction
253
Connection JavaDoc c;
254     long tid = request.getTransactionId();
255
256     try
257     {
258       c = backend.getConnectionForTransactionAndLazyBeginIfNeeded(request, cm);
259     }
260     catch (UnreachableBackendException ube)
261     {
262       SQLException JavaDoc se = new SQLException JavaDoc("Backend " + backend.getName()
263           + " is no more reachable.");
264       try
265       {
266         notifyFailure(backendThread, -1, se);
267       }
268       catch (SQLException JavaDoc ignore)
269       {
270       }
271       // Disable this backend (it is no more in sync) by killing the backend
272
// thread
273
backendThread.getLoadBalancer().disableBackend(backend, true);
274       String JavaDoc msg = Translate.get(
275           "loadbalancer.backend.disabling.unreachable", backend.getName());
276       logger.error(msg);
277       endUserLogger.error(msg);
278       throw se;
279     }
280     catch (NoTransactionStartWhenDisablingException e)
281     {
282       // Backend is disabling, we do not execute queries except the one in the
283
// transaction we already started. Just notify the completion for the
284
// others.
285
notifyCompletion(backendThread);
286       return;
287     }
288     catch (SQLException JavaDoc e1)
289     {
290       SQLException JavaDoc se = new SQLException JavaDoc(
291           "Unable to get connection for transaction " + tid);
292       try
293       { // All backends failed, just ignore
294
if (!notifyFailure(backendThread, request.getTimeout() * 1000L, se))
295           return;
296       }
297       catch (SQLException JavaDoc ignore)
298       {
299       }
300       // Disable this backend (it is no more in sync) by killing the
301
// backend thread
302
backendThread.getLoadBalancer().disableBackend(backend, true);
303       String JavaDoc msg = "Request '"
304           + request.getSqlShortForm(backend.getSqlShortFormLength())
305           + "' failed on backend " + backend.getName() + " but " + getSuccess()
306           + " succeeded (" + se + ")";
307       logger.error(msg);
308       endUserLogger.error(Translate.get(
309           "loadbalancer.backend.disabling", backend.getName()));
310       throw new SQLException JavaDoc(msg);
311     }
312
313     // Sanity check
314
if (c == null)
315     { // Bad connection
316
SQLException JavaDoc se = new SQLException JavaDoc(
317           "Unable to retrieve connection for transaction " + tid);
318       try
319       { // All backends failed, just ignore
320
if (!notifyFailure(backendThread, request.getTimeout() * 1000L, se))
321           return;
322       }
323       catch (SQLException JavaDoc ignore)
324       {
325       }
326       // Disable this backend (it is no more in sync) by killing the
327
// backend thread
328
backendThread.getLoadBalancer().disableBackend(backend, true);
329       String JavaDoc msg = "Request '"
330           + request.getSqlShortForm(backend.getSqlShortFormLength())
331           + "' failed on backend " + backend.getName() + " but " + getSuccess()
332           + " succeeded (" + se + ")";
333       logger.error(msg);
334       endUserLogger.error(Translate.get(
335           "loadbalancer.backend.disabling", backend.getName()));
336       throw new SQLException JavaDoc(msg);
337     }
338
339     // Execute Query
340
try
341     {
342       result = AbstractLoadBalancer
343           .executeStatementExecuteUpdateWithKeysOnBackend(request, backend,
344               backendThread, c, metadataCache);
345
346       backend.updateDatabaseBackendSchema(request);
347     }
348     catch (Exception JavaDoc e)
349     {
350       try
351       { // All backends failed, just ignore
352
if (!notifyFailure(backendThread, request.getTimeout() * 1000L, e))
353         {
354           result = null;
355           return;
356         }
357       }
358       catch (SQLException JavaDoc ignore)
359       {
360       }
361       // Disable this backend (it is no more in sync) by killing the backend
362
// thread
363
backendThread.getLoadBalancer().disableBackend(backend, true);
364       String JavaDoc msg = "Request '"
365           + request.getSqlShortForm(backend.getSqlShortFormLength())
366           + "' failed on backend " + backend.getName() + " but " + getSuccess()
367           + " succeeded (" + e + ")";
368       logger.error(msg);
369       endUserLogger.error(Translate.get(
370           "loadbalancer.backend.disabling", backend.getName()));
371       throw new SQLException JavaDoc(msg);
372     }
373   }
374
375   /**
376    * @see org.continuent.sequoia.controller.loadbalancer.tasks.AbstractTask#getRequest()
377    */

378   public AbstractRequest getRequest()
379   {
380     return request;
381   }
382
383   /**
384    * Returns the update count and auto generated keys.
385    *
386    * @return a <code>GeneratedKeysResult</code> object
387    */

388   public GeneratedKeysResult getResult()
389   {
390     return result;
391   }
392
393   /**
394    * @see org.continuent.sequoia.controller.loadbalancer.tasks.AbstractTask#getTransactionId()
395    */

396   public long getTransactionId()
397   {
398     return request.getTransactionId();
399   }
400
401   /**
402    * @see org.continuent.sequoia.controller.loadbalancer.tasks.AbstractTask#isAutoCommit()
403    */

404   public boolean isAutoCommit()
405   {
406     return request.isAutoCommit();
407   }
408
409   /**
410    * @see java.lang.Object#equals(java.lang.Object)
411    */

412   public boolean equals(Object JavaDoc other)
413   {
414     if ((other == null)
415         || !(other instanceof StatementExecuteUpdateWithKeysTask))
416       return false;
417
418     StatementExecuteUpdateWithKeysTask seuwk = (StatementExecuteUpdateWithKeysTask) other;
419     return this.request.equals(seuwk.getRequest());
420   }
421
422   /**
423    * @see java.lang.Object#hashCode()
424    */

425   public int hashCode()
426   {
427     return (int) request.getId();
428   }
429
430   /**
431    * @see java.lang.Object#toString()
432    */

433   public String JavaDoc toString()
434   {
435     if (request.isAutoCommit())
436       return "Autocommit StatementExecuteUpdateWithKeysTask ("
437           + request.getUniqueKey() + ")";
438     else
439       return "StatementExecuteUpdateWithKeysTask from transaction "
440           + request.getTransactionId() + " (" + request.getUniqueKey() + ")";
441   }
442
443 }
Popular Tags