KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > jts > CosTransactions > DelegatedTimeoutManager


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the License). You may not use this file except in
5  * compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * https://glassfish.dev.java.net/public/CDDLv1.0.html or
9  * glassfish/bootstrap/legal/CDDLv1.0.txt.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * Header Notice in each file and include the License file
15  * at glassfish/bootstrap/legal/CDDLv1.0.txt.
16  * If applicable, add the following below the CDDL Header,
17  * with the fields enclosed by brackets [] replaced by
18  * you own identifying information:
19  * "Portions Copyrighted [year] [name of copyright owner]"
20  *
21  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
22  */

23
24 /*
25  * Copyright 2004-2005 Sun Microsystems, Inc. All rights reserved.
26  * Use is subject to license terms.
27  */

28
29 package com.sun.jts.CosTransactions;
30
31 import java.util.*;
32
33 import org.omg.CosTransactions.*;
34 import com.sun.jts.jtsxa.XID;
35
36 import com.sun.jts.trace.*;
37
38 import java.util.logging.Logger JavaDoc;
39 import java.util.logging.Level JavaDoc;
40 import com.sun.logging.LogDomains;
41 import com.sun.jts.utils.LogFormatter;
42
43 /**
44  * This class records state for timing out transactions, and runs a thread
45  * which performs occasional checks to time out transactions. For each log
46  * location, which requires delegated recovery, an instance of this will be
47  * created. Done as part of delegated recovery support.
48  * th
49  *
50  * @version 0.01
51  *
52  *
53  * @see
54  */

55
56 class DelegatedTimeoutManager {
57     /**
58      * Constants which define the types of timeout possible.
59      */

60     static final int CANCEL_TIMEOUT = 0;
61     static final int NO_TIMEOUT = 0;
62     static final int ACTIVE_TIMEOUT = 1;
63     static final int IN_DOUBT_TIMEOUT = 2;
64     
65     /**
66      * this attribute indicates whether initialisation has been started.
67      */

68     private static boolean initialised = false;
69     
70     private Hashtable pendingTimeouts = new Hashtable();
71     private Hashtable indoubtTimeouts = new Hashtable();
72     private DelegatedTimeoutThread timeoutThread = null;
73     private boolean timeoutActive = false;
74     private boolean quiescing = false;
75     private boolean isSetTimeout = false;
76     private String JavaDoc logPath = null;
77     
78         /*
79                 Logger to log transaction messages
80          */

81     static Logger JavaDoc _logger = LogDomains.getLogger(LogDomains.TRANSACTION_LOGGER);
82     /**
83      * Initialises the static state of the TimeoutManager class.
84      *
85      * @param
86      *
87      * @return
88      *
89      * @see
90      */

91     /**
92      * synchronized static void initialise() {
93      *
94      * // If already initialised, return immediately.
95      *
96      * if (initialised) {
97      * return;
98      * }
99      *
100      * initialised = true;
101      *
102      * // Start the timeout thread.
103      *
104      * if (!timeoutActive && timeoutThread == null) {
105      * // timeoutThread = new TimeoutThread();
106      * // timeoutThread.start();
107      * timeoutActive = true;
108      * }
109      * }
110      **/

111     
112     DelegatedTimeoutManager() {
113     }
114     
115     DelegatedTimeoutManager(String JavaDoc logPath) {
116         this.logPath = logPath;
117     }
118     
119     
120     synchronized void initSetTimeout() {
121         if (isSetTimeout)
122             return;
123         isSetTimeout = true;
124         timeoutThread = new DelegatedTimeoutThread(this);
125         timeoutThread.start();
126     }
127     
128     /**
129      * Sets the timeout for the transaction to the specified type and time in
130      * seconds.
131      * <p>
132      * If the type is none, the timeout for the transaction is
133      * cancelled, otherwise the current timeout for the transaction is modified
134      * to be of the new type and duration.
135      *
136      * @param localTID The local identifier for the transaction.
137      * @param timeoutType The type of timeout to establish.
138      * @param seconds The length of the timeout.
139      *
140      * @return Indicates success of the operation.
141      *
142      * @see
143      */

144     boolean setTimeout(Long JavaDoc localTID, int timeoutType,
145     int seconds) {
146         
147         boolean result = true;
148         
149         // Modify the timeout to the required type and value.
150

151         DelegatedTimeoutInfo timeoutInfo = null;
152         
153         switch (timeoutType) {
154             
155             // If the new type is active or in_doubt, then create a
156
// new TimeoutInfo if necessary, and set up the type and interval.
157

158             case DelegatedTimeoutManager.ACTIVE_TIMEOUT :
159                 if (!isSetTimeout) {
160                     initSetTimeout();
161                 }
162                 timeoutInfo = new DelegatedTimeoutInfo();
163                 timeoutInfo.expireTime =
164                 new Date().getTime() + seconds * 1000;
165                 timeoutInfo.localTID = localTID;
166                 timeoutInfo.timeoutType = timeoutType;
167                 pendingTimeouts.put(localTID,timeoutInfo);
168                 break;
169             case TimeoutManager.IN_DOUBT_TIMEOUT :
170                 if (!isSetTimeout) {
171                     initSetTimeout();
172                     // isSetTimeout = true;
173
}
174                 timeoutInfo = new DelegatedTimeoutInfo();
175                 timeoutInfo.expireTime =
176                 new Date().getTime() + seconds * 1000;
177                 timeoutInfo.localTID = localTID;
178                 timeoutInfo.timeoutType = timeoutType;
179                 indoubtTimeouts.put(localTID,timeoutInfo);
180                 break;
181                 
182                 // For any other type, remove the timeout if there is one.
183

184             default:
185                 if (!isSetTimeout)
186                     break;
187                 result = (pendingTimeouts.remove(localTID) != null);
188                 if (!result)
189                     result = (indoubtTimeouts.remove(localTID) != null);
190                 
191                 // If the transaction service is quiescing and
192
// there are no more pending timeouts,
193
// deactivate timeout and stop the timeout thread.
194

195                 if (quiescing && pendingTimeouts.isEmpty() && indoubtTimeouts.isEmpty()) {
196                     timeoutThread.stop();
197                     timeoutActive = false;
198                     // pendingTimeouts = null;
199
}
200                 break;
201         }
202         return result;
203     }
204     
205     /**
206      * Takes appropriate action for a timeout.
207      * <p>
208      * The type fo timeout is given, and the transaction represented by the
209      * Coordinator and its local identifier.
210      * <p>
211      * This method does not reference the TimeoutManager's state directly
212      * and so does not need to be synchronized.
213      *
214      * @param localTID The local identifier for the transaction.
215      * @param timeoutType The type of timeout.
216      *
217      * @return
218      *
219      * @see
220      */

221     void timeoutCoordinator(Long JavaDoc localTID, int timeoutType) {
222         
223         // Look up the Coordinator for the transaction.
224
// If there is none, then the transaction has already gone.
225
// Otherwise do something with the transaction.
226

227         
228         CoordinatorImpl coord = DelegatedRecoveryManager.getLocalCoordinator(localTID, logPath);
229         if (coord == null) {
230             if(_logger.isLoggable(Level.FINER)) {
231                 _logger.logp(Level.FINER,"DelegatedTimeoutManager","timeoutCoordinator()",
232                 "DelegatedRecoveryManager.getLocalCoordinator() returned null,"+
233                 "which means txn is done. Setting timeout type to CANCEL_TIMEOUT");
234             }
235             setTimeout(localTID, TimeoutManager.CANCEL_TIMEOUT, 0);
236         } else {
237             synchronized (coord) {
238                 boolean[] isRoot = new boolean[1];
239                 
240                 switch (timeoutType) {
241                     
242                     // If active, then attempt to roll the transaction back.
243

244                     case DelegatedTimeoutManager.ACTIVE_TIMEOUT :
245                         if(_logger.isLoggable(Level.FINER)) {
246                             _logger.logp(Level.FINER,"DelegatedTimeoutManager","timeoutCoordinator()",
247                             "DelegatedTimeoutManager.timeoutCoordinator():case ACTIVE_TIMEOUT"+
248                             "DelegatedRecoveryManager.getLocalCoordinator() returned non-null,"+
249                             "which means txn is still around. Rolling back the"+
250                             "transaction...: GTID is : " +
251                             ((TopCoordinator)coord).superInfo.globalTID.toString());
252                         }
253                         try {
254                             // coord.rollback(true);
255
coord.rollback_only();
256                         } catch (Throwable JavaDoc exc) {}
257                         break;
258                         
259                         // If in doubt, it must be a TopCoordinator.
260
// In that case replay_completion needs to be driven.
261
// This is done by telling the TopCoordinator to act as
262
// if in recovery. The result is then used to
263
// determine what to do with the Coordinator.
264

265                     case DelegatedTimeoutManager.IN_DOUBT_TIMEOUT :
266                         if(_logger.isLoggable(Level.FINER)) {
267                             _logger.logp(Level.FINER,"DelegatedTimeoutManager","timeoutCoordinator()",
268                             "DelegatedTimeoutManager.timeoutCoordinator():case IN_DOUBT_TIMEOUT"+
269                             "DelegatedRecoveryManager.getLocalCoordinator() returned non-null,"+
270                             "which means txn is still around. Invoking recover(boolean)"+
271                             "on TopCoordinator...: GTID is: "+
272                             ((TopCoordinator)coord).superInfo.globalTID.toString());
273                         }
274                         Status state = ((TopCoordinator) coord).recover(isRoot);
275                         
276                         if (state == Status.StatusUnknown) {
277                             
278                             // If the outcome is not currently known, we do
279
// nothing with the transaction, as we expect to
280
// eventually get an outcome from the parent.
281

282                             // GDH put out warning in case this state
283
// continues for a long time.
284
_logger.log(Level.WARNING, "jts.transaction_resync_from_orginator_failed");
285                             
286                         } else if (state == Status.StatusCommitted) {
287                             
288                             // For committed or rolled back, proceed with
289
// completion of the transaction, regardless of whether
290
// it is the root or a subordinate. This will
291
// result in the removal of the in-doubt timeout.
292

293                             try {
294                                 ((TopCoordinator)coord).commit();
295                                 if (isRoot[0]) {
296                                     ((TopCoordinator) coord).
297                                     afterCompletion(state);
298                                 }
299                             } catch (Throwable JavaDoc exc) {}
300                         } else {
301                             // By default, roll the transaction back.
302
try {
303                                 ((TopCoordinator) coord).rollback(true);
304                                 if (isRoot[0]) {
305                                     ((TopCoordinator) coord).
306                                     afterCompletion(Status.StatusRolledBack);
307                                 }
308                             } catch (Throwable JavaDoc exc) {}
309                         }
310                         
311                         break;
312                         
313                     default:
314                         // Otherwise do nothing.
315
break;
316                 }
317             }
318         }
319     }
320     
321     /**
322      * Periodically checks the existing timeouts.
323      * <p>
324      * This is done to discover if any transactions have overrun their allotted
325      * time. Those which have are returned as an Enumeration.
326      * <p>
327      * Note that this method should not do anything that will cause a
328      * synchronized method in the RecoveryManager to be called, as this could
329      * cause a deadlock when RecoveryManager methods on other threads call
330      * setTimeout.
331      *
332      * @param
333      *
334      * @return The information for transactions which have timed out.
335      *
336      * @see
337      */

338     Enumeration checkTimeouts() {
339         if (!isSetTimeout)
340             return null;
341         
342         Enumeration result = null;
343         
344         // When woken up, go through all current timeouts and identify those
345
// which have expired.
346

347         if (timeoutActive && ((pendingTimeouts.size() != 0) || (indoubtTimeouts.size() != 0))) {
348             Vector timedOut = null;
349             
350             Enumeration timeouts = null;
351             
352             synchronized (pendingTimeouts) {
353                 timeouts = pendingTimeouts.elements();
354                 
355                 while (timeouts.hasMoreElements()) {
356                     
357                     DelegatedTimeoutInfo timeoutInfo = (DelegatedTimeoutInfo)timeouts.nextElement();
358                     
359                     // For each timeout in the list, check whether it has expired.
360
// If so, look up the Coordinator and roll it back.
361

362                     if (new Date().getTime() > timeoutInfo.expireTime) {
363                         
364                         // Add the TimeoutInfo to the queue of
365
//those that have timed out.
366

367                         if (timedOut == null) {
368                             timedOut = new Vector();
369                         }
370                         
371                         timedOut.addElement(timeoutInfo);
372                     }
373                 }
374             }
375             
376             synchronized (indoubtTimeouts) {
377                 
378                 timeouts = indoubtTimeouts.elements();
379                 
380                 while (timeouts.hasMoreElements()) {
381                     
382                     DelegatedTimeoutInfo timeoutInfo = (DelegatedTimeoutInfo)timeouts.nextElement();
383                     
384                     // For each timeout in the list, check whether it has expired.
385
// If so, look up the Coordinator and roll it back.
386

387                     if (new Date().getTime() > timeoutInfo.expireTime) {
388                         
389                         // Add the TimeoutInfo to the queue of
390
//those that have timed out.
391

392                         if (timedOut == null) {
393                             timedOut = new Vector();
394                         }
395                         
396                         timedOut.addElement(timeoutInfo);
397                     }
398                 }
399                 
400             }
401             // Enumerate the transactions which have timed out.
402

403             if (timedOut != null) {
404                 result = timedOut.elements();
405             }
406         }
407         
408         // The remainder of the timeout processing is not carried out here
409
// because we would get deadlocked with addCoordinator or
410
// removeCoordinator that also update the timeout list. Hence the
411
// returned enumeration, which may be processed with
412
// no concurrency control.
413

414         return result;
415     }
416     
417     /**
418      * @return a set of in-doubt transaction ids.
419      */

420     XID[] getInDoubtXids() {
421         
422         synchronized (indoubtTimeouts) {
423             Vector inDoubtList = new Vector();
424             
425             Enumeration timeouts = indoubtTimeouts.elements();
426             
427             while (timeouts.hasMoreElements()) {
428                 
429                 DelegatedTimeoutInfo timeoutInfo = (DelegatedTimeoutInfo) timeouts.nextElement();
430                 
431                 // Look up the Coordinator for the transaction.
432
// If there is none, then the transaction has already gone.
433
// Otherwise do something with the transaction.
434

435                 CoordinatorImpl coord =
436                 DelegatedRecoveryManager.getLocalCoordinator(timeoutInfo.localTID, logPath);
437                 
438                 if (coord != null) {
439                     XID xid = new XID();
440                     xid.copy(coord.getGlobalTID());
441                     inDoubtList.addElement(xid);
442                 }
443             }
444             
445             return (XID[]) inDoubtList.toArray(new XID[] {});
446         }
447     }
448     
449     /**
450      * Returns the amount of time left before the given transaction times out.
451      *
452      * @param localTID The local identifier for the transaction.
453      *
454      * @return The time left. If there is no timeout for the transaction,
455      * this value will be negative. If the timeout period has been
456      * exceeded, this value will be zero.
457      *
458      * @see
459      */

460     long timeLeft(Long JavaDoc localTID) {
461         
462         DelegatedTimeoutInfo timeoutInfo = (DelegatedTimeoutInfo) pendingTimeouts.get(localTID);
463         if (timeoutInfo == null)
464             timeoutInfo = (DelegatedTimeoutInfo) indoubtTimeouts.get(localTID);
465         long result = -1;
466         if (timeoutInfo != null) {
467             result = timeoutInfo.expireTime - new Date().getTime();
468             if (result < 0) {
469                 result = 0;
470             }
471         }
472         
473         return result;
474     }
475     
476     /**
477      * Informs the TimeoutManager that the transaction service
478      * is being shut down. For immediate shutdown, the timeout thread is
479      * stopped and all timeout information discarded.
480      *
481      * For quiesce, the timeout thread is stopped when there are no running
482      * transactions left.
483      *
484      * @param immediate Indicates whether to stop immediately.
485      *
486      * @return
487      *
488      * @see
489      */

490     void shutdown(boolean immediate) {
491         
492         // For immediate, kill the timeout thread and throw
493
// away all information. Also, if there are no pending
494
// timeouts, there is nothing to quiesce so
495
// shutdown immediately regardless.
496

497         if (immediate ||
498         pendingTimeouts == null || pendingTimeouts.isEmpty()) {
499             if (timeoutThread != null) {
500                 timeoutThread.stop();
501             }
502             
503             if (pendingTimeouts != null) {
504                 pendingTimeouts.clear();
505             }
506             
507             pendingTimeouts = null;
508             timeoutThread = null;
509             timeoutActive = false;
510         } else {
511             quiescing = true;
512         }
513     }
514     
515 }
516
517 /**
518  * This class records information for a timeout for a transaction.
519  *
520  * @version 0.1
521  *
522  * @author Simon Holdsworth, IBM Corporation
523  *
524  * @see
525  */

526
527 //----------------------------------------------------------------------------
528
// CHANGE HISTORY
529
//
530
// Version By Change Description
531
// 0.1 SAJH Initial implementation.
532
//----------------------------------------------------------------------------
533

534 class DelegatedTimeoutInfo extends Object JavaDoc {
535     Long JavaDoc localTID = null;
536     long expireTime = 0;
537     int timeoutType = TimeoutManager.NO_TIMEOUT;
538 }
539
540 /**
541  * This class represents a thread on which the TimeoutManager can perform
542  * timeout checking.
543  *
544  * @version 0.01
545  *
546  *
547  * @see
548  */

549
550
551 class DelegatedTimeoutThread extends Thread JavaDoc {
552     
553     private int TIMEOUT_INTERVAL ;
554     private DelegatedTimeoutManager tmoutMgr = null;
555     
556     static Logger JavaDoc _logger = LogDomains.getLogger(LogDomains.TRANSACTION_LOGGER);
557     /**
558      * TimeoutThread constructor.
559      * <p>
560      * This sets the thread name, and sets the thread to be a daemon thread so
561      * that it does not prevent the process from terminating.
562      *
563      * @param
564      *
565      * @return
566      *
567      * @see
568      */

569     DelegatedTimeoutThread(DelegatedTimeoutManager timeoutMgr) {
570         setName("Delegated JTS Timeout Thread"/*#Frozen*/);
571         setDaemon(true);
572         tmoutMgr = timeoutMgr;
573         try{
574             String JavaDoc timeout_interval = Configuration.getPropertyValue(Configuration.TIMEOUT_INTERVAL);
575             if(timeout_interval!=null){
576                 TIMEOUT_INTERVAL= Integer.parseInt(timeout_interval);
577                 TIMEOUT_INTERVAL*=1000;
578                 if(TIMEOUT_INTERVAL<10000)
579                     TIMEOUT_INTERVAL=10000;
580             }
581             else{
582                 TIMEOUT_INTERVAL=10000;
583             }
584         }catch(Exception JavaDoc e){
585             TIMEOUT_INTERVAL=10000;
586         }
587     }
588     
589     /**
590      * Performs timeout checking on a regular basis (every ten seconds or so).
591      *
592      * @param
593      *
594      * @return
595      *
596      * @see
597      */

598     public void run() {
599         try {
600             while (true) {
601                 
602                 // Sleep for a while between checks.
603

604                 Thread.sleep(TIMEOUT_INTERVAL);
605                 
606                 // Perform timeout checks, getting a list of timed-out
607
// transactions.
608

609                 Enumeration timedOut = tmoutMgr.checkTimeouts();
610                 
611                 // Now we must go through the list, telling each
612
// timed-out Coordinator to do something appropriate.
613

614                 if (timedOut != null) {
615                     while (timedOut.hasMoreElements()) {
616                         DelegatedTimeoutInfo timeoutInfo =
617                         (DelegatedTimeoutInfo) timedOut.nextElement();
618                         
619                         // Look up the Coordinator and tell it to roll back
620
// if it still exists. Note that we rely on the
621
// Coordinator calling removeCoordinator when it
622
// has finished, which will remove the timeout from
623
// the list, and remove other associations as well.
624

625                         tmoutMgr.
626                         timeoutCoordinator(timeoutInfo.localTID,
627                         timeoutInfo.timeoutType);
628                     }
629                 }
630             }
631         } catch (InterruptedException JavaDoc exc) {
632             _logger.log(Level.INFO,"jts.time_out_thread_stopped");
633         }
634     }
635 }
636
Popular Tags