KickJava   Java API By Example, From Geeks To Geeks.

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


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 //----------------------------------------------------------------------------
30
//
31
// Module: TimeoutManager.java
32
//
33
// Description: Transaction time-out manager.
34
//
35
// Product: com.sun.jts.CosTransactions
36
//
37
// Author: Simon Holdsworth
38
//
39
// Date: March, 1997
40
//
41
// Copyright (c): 1995-1997 IBM Corp.
42
//
43
// The source code for this program is not published or otherwise divested
44
// of its trade secrets, irrespective of what has been deposited with the
45
// U.S. Copyright Office.
46
//
47
// This software contains confidential and proprietary information of
48
// IBM Corp.
49
//----------------------------------------------------------------------------
50

51 package com.sun.jts.CosTransactions;
52
53 import java.util.*;
54
55 import org.omg.CosTransactions.*;
56 import com.sun.jts.jtsxa.XID;
57
58 import com.sun.jts.trace.*;
59
60 import java.util.logging.Logger JavaDoc;
61 import java.util.logging.Level JavaDoc;
62 import com.sun.logging.LogDomains;
63 import com.sun.jts.utils.LogFormatter;
64
65 /**
66  * This class records state for timing out transactions, and runs a thread
67  * which performs occasional checks to time out transactions.
68  *
69  * @version 0.01
70  *
71  * @author Simon Holdsworth, IBM Corporation
72  *
73  * @see
74 */

75
76 //----------------------------------------------------------------------------
77
// CHANGE HISTORY
78
//
79
// Version By Change Description
80
// 0.01 SAJH Initial implementation.
81
//----------------------------------------------------------------------------
82

83 class TimeoutManager {
84     /**
85      * Constants which define the types of timeout possible.
86      */

87     static final int CANCEL_TIMEOUT = 0;
88     static final int NO_TIMEOUT = 0;
89     static final int ACTIVE_TIMEOUT = 1;
90     static final int IN_DOUBT_TIMEOUT = 2;
91
92     /**
93      * this attribute indicates whether initialisation has been started.
94      */

95     private static boolean initialised = false;
96
97     private static Hashtable pendingTimeouts = new Hashtable();
98     private static Hashtable indoubtTimeouts = new Hashtable();
99     private static TimeoutThread timeoutThread = null;
100     private static boolean timeoutActive = false;
101     private static boolean quiescing = false;
102     private static boolean isSetTimeout = false;
103
104     /*
105         Logger to log transaction messages
106     */

107     static Logger JavaDoc _logger = LogDomains.getLogger(LogDomains.TRANSACTION_LOGGER);
108     /**
109      * Initialises the static state of the TimeoutManager class.
110      *
111      * @param
112      *
113      * @return
114      *
115      * @see
116      */

117     synchronized static void initialise() {
118
119         // If already initialised, return immediately.
120

121         if (initialised) {
122             return;
123         }
124
125         initialised = true;
126
127         // Start the timeout thread.
128

129         if (!timeoutActive && timeoutThread == null) {
130            // timeoutThread = new TimeoutThread();
131
// timeoutThread.start();
132
timeoutActive = true;
133         }
134     }
135
136
137     static synchronized void initSetTimeout() {
138     if (isSetTimeout)
139        return;
140         isSetTimeout = true;
141         timeoutThread = new TimeoutThread();
142         timeoutThread.start();
143     }
144
145     /**
146      * Sets the timeout for the transaction to the specified type and time in
147      * seconds.
148      * <p>
149      * If the type is none, the timeout for the transaction is
150      * cancelled, otherwise the current timeout for the transaction is modified
151      * to be of the new type and duration.
152      *
153      * @param localTID The local identifier for the transaction.
154      * @param timeoutType The type of timeout to establish.
155      * @param seconds The length of the timeout.
156      *
157      * @return Indicates success of the operation.
158      *
159      * @see
160      */

161      static boolean setTimeout(Long JavaDoc localTID, int timeoutType,
162                                            int seconds) {
163
164         boolean result = true;
165
166         // Modify the timeout to the required type and value.
167

168         if (timeoutActive) {
169
170             TimeoutInfo timeoutInfo = null;
171
172             switch (timeoutType) {
173
174             // If the new type is active or in_doubt, then create a
175
// new TimeoutInfo if necessary, and set up the type and interval.
176

177             case TimeoutManager.ACTIVE_TIMEOUT :
178          if (!isSetTimeout) {
179              initSetTimeout();
180                  }
181                  timeoutInfo = new TimeoutInfo();
182                  timeoutInfo.expireTime =
183                     new Date().getTime() + seconds * 1000;
184                  timeoutInfo.localTID = localTID;
185                  timeoutInfo.timeoutType = timeoutType;
186                  pendingTimeouts.put(localTID,timeoutInfo);
187                  break;
188             case TimeoutManager.IN_DOUBT_TIMEOUT :
189          if (!isSetTimeout) {
190              initSetTimeout();
191              // isSetTimeout = true;
192
}
193                 timeoutInfo = new TimeoutInfo();
194                 timeoutInfo.expireTime =
195                     new Date().getTime() + seconds * 1000;
196                 timeoutInfo.localTID = localTID;
197                 timeoutInfo.timeoutType = timeoutType;
198                 indoubtTimeouts.put(localTID,timeoutInfo);
199                 break;
200
201             // For any other type, remove the timeout if there is one.
202

203             default:
204         if (!isSetTimeout)
205           break;
206                    result = (pendingTimeouts.remove(localTID) != null);
207            if (!result)
208                       result = (indoubtTimeouts.remove(localTID) != null);
209
210                     // If the transaction service is quiescing and
211
// there are no more pending timeouts,
212
// deactivate timeout and stop the timeout thread.
213

214                     if (quiescing && pendingTimeouts.isEmpty() && indoubtTimeouts.isEmpty()) {
215                         timeoutThread.stop();
216                         timeoutActive = false;
217                         // pendingTimeouts = null;
218
}
219                 break;
220             }
221         } else {
222             // If timeouts are not active, just return false.
223
result = false;
224         }
225
226         return result;
227     }
228
229     /**
230      * Takes appropriate action for a timeout.
231      * <p>
232      * The type fo timeout is given, and the transaction represented by the
233      * Coordinator and its local identifier.
234      * <p>
235      * This method does not reference the TimeoutManager's state directly
236      * and so does not need to be synchronized.
237      *
238      * @param localTID The local identifier for the transaction.
239      * @param timeoutType The type of timeout.
240      *
241      * @return
242      *
243      * @see
244      */

245     static void timeoutCoordinator(Long JavaDoc localTID, int timeoutType) {
246
247         // Look up the Coordinator for the transaction.
248
// If there is none, then the transaction has already gone.
249
// Otherwise do something with the transaction.
250

251
252         CoordinatorImpl coord = RecoveryManager.getLocalCoordinator(localTID);
253         if (coord == null) {
254             if(_logger.isLoggable(Level.FINER))
255             {
256                 _logger.logp(Level.FINER,"TimeoutManager","timeoutCoordinator()",
257             "RecoveryManager.getLocalCoordinator() returned null,"+
258             "which means txn is done. Setting timeout type to CANCEL_TIMEOUT");
259             }
260             TimeoutManager.setTimeout(localTID,
261                                       TimeoutManager.CANCEL_TIMEOUT,
262                                       0);
263         } else {
264             synchronized (coord) {
265                 boolean[] isRoot = new boolean[1];
266
267                 switch (timeoutType) {
268
269                 // If active, then attempt to roll the transaction back.
270

271                 case TimeoutManager.ACTIVE_TIMEOUT :
272                     if(_logger.isLoggable(Level.FINER))
273                     {
274                         _logger.logp(Level.FINER,"TimeoutManager","timeoutCoordinator()",
275                                      "TimeoutManager.timeoutCoordinator():case ACTIVE_TIMEOUT"+
276                                      "RecoveryManager.getLocalCoordinator() returned non-null,"+
277                                      "which means txn is still around. Marking for Rollback the"+
278                                      "transaction...: GTID is : " +
279                                      ((TopCoordinator)coord).superInfo.globalTID.toString());
280                     }
281                     try {
282                         // coord.rollback(true);
283
coord.rollback_only();
284                     } catch (Throwable JavaDoc exc) {}
285                     break;
286
287                     // If in doubt, it must be a TopCoordinator.
288
// In that case replay_completion needs to be driven.
289
// This is done by telling the TopCoordinator to act as
290
// if in recovery. The result is then used to
291
// determine what to do with the Coordinator.
292

293                 case TimeoutManager.IN_DOUBT_TIMEOUT :
294                     if(_logger.isLoggable(Level.FINER))
295                     {
296                         _logger.logp(Level.FINER,"TimeoutManager","timeoutCoordinator()",
297                                      "TimeoutManager.timeoutCoordinator():case IN_DOUBT_TIMEOUT"+
298                                      "RecoveryManager.getLocalCoordinator() returned non-null,"+
299                                      "which means txn is still around. Invoking recover(boolean)"+
300                                      "on TopCoordinator...: GTID is: "+
301                                      ((TopCoordinator)coord).superInfo.globalTID.toString());
302                     }
303                     Status state = ((TopCoordinator) coord).recover(isRoot);
304
305                     if (state == Status.StatusUnknown) {
306                     
307                         // If the outcome is not currently known, we do
308
// nothing with the transaction, as we expect to
309
// eventually get an outcome from the parent.
310

311                         // GDH put out warning in case this state
312
// continues for a long time.
313
_logger.log(Level.WARNING, "jts.transaction_resync_from_orginator_failed");
314
315                     } else if (state == Status.StatusCommitted) {
316
317                         // For committed or rolled back, proceed with
318
// completion of the transaction, regardless of whether
319
// it is the root or a subordinate. This will
320
// result in the removal of the in-doubt timeout.
321

322                         try {
323                             ((TopCoordinator)coord).commit();
324                             if (isRoot[0]) {
325                                 ((TopCoordinator) coord).
326                                     afterCompletion(state);
327                             }
328                         } catch (Throwable JavaDoc exc) {}
329                     } else {
330                         // By default, roll the transaction back.
331
try {
332                             ((TopCoordinator) coord).rollback(true);
333                             if (isRoot[0]) {
334                                 ((TopCoordinator) coord).
335                                     afterCompletion(Status.StatusRolledBack);
336                             }
337                         } catch (Throwable JavaDoc exc) {}
338                     }
339
340                     break;
341
342                 default:
343                     // Otherwise do nothing.
344
break;
345                 }
346             }
347         }
348     }
349
350     /**
351      * Periodically checks the existing timeouts.
352      * <p>
353      * This is done to discover if any transactions have overrun their allotted
354      * time. Those which have are returned as an Enumeration.
355      * <p>
356      * Note that this method should not do anything that will cause a
357      * synchronized method in the RecoveryManager to be called, as this could
358      * cause a deadlock when RecoveryManager methods on other threads call
359      * setTimeout.
360      *
361      * @param
362      *
363      * @return The information for transactions which have timed out.
364      *
365      * @see
366      */

367      static Enumeration checkTimeouts() {
368         if (!isSetTimeout)
369            return null;
370
371         Enumeration result = null;
372
373         // When woken up, go through all current timeouts and identify those
374
// which have expired.
375

376         if (timeoutActive && ((pendingTimeouts.size() != 0) || (indoubtTimeouts.size() != 0))) {
377             Vector timedOut = null;
378
379             Enumeration timeouts = null;
380           
381             synchronized (pendingTimeouts) {
382                 timeouts = pendingTimeouts.elements();
383
384                 while (timeouts.hasMoreElements()) {
385
386                     TimeoutInfo timeoutInfo = (TimeoutInfo)timeouts.nextElement();
387
388                     // For each timeout in the list, check whether it has expired.
389
// If so, look up the Coordinator and roll it back.
390

391                     if (new Date().getTime() > timeoutInfo.expireTime) {
392
393                        // Add the TimeoutInfo to the queue of
394
//those that have timed out.
395

396                        if (timedOut == null) {
397                            timedOut = new Vector();
398                        }
399
400                        timedOut.addElement(timeoutInfo);
401                     }
402                }
403             }
404
405         synchronized (indoubtTimeouts) {
406
407                 timeouts = indoubtTimeouts.elements();
408
409                 while (timeouts.hasMoreElements()) {
410
411                     TimeoutInfo timeoutInfo = (TimeoutInfo)timeouts.nextElement();
412
413                     // For each timeout in the list, check whether it has expired.
414
// If so, look up the Coordinator and roll it back.
415

416                     if (new Date().getTime() > timeoutInfo.expireTime) {
417
418                        // Add the TimeoutInfo to the queue of
419
//those that have timed out.
420

421                        if (timedOut == null) {
422                            timedOut = new Vector();
423                        }
424
425                        timedOut.addElement(timeoutInfo);
426                     }
427                 }
428
429             }
430             // Enumerate the transactions which have timed out.
431

432             if (timedOut != null) {
433                 result = timedOut.elements();
434             }
435            }
436
437         // The remainder of the timeout processing is not carried out here
438
// because we would get deadlocked with addCoordinator or
439
// removeCoordinator that also update the timeout list. Hence the
440
// returned enumeration, which may be processed with
441
// no concurrency control.
442

443         return result;
444     }
445
446     /**
447      * @return a set of in-doubt transaction ids.
448      */

449     static XID[] getInDoubtXids() {
450         
451        synchronized (indoubtTimeouts) {
452         Vector inDoubtList = new Vector();
453         
454         Enumeration timeouts = indoubtTimeouts.elements();
455
456         while (timeouts.hasMoreElements()) {
457
458             TimeoutInfo timeoutInfo = (TimeoutInfo) timeouts.nextElement();
459
460             // Look up the Coordinator for the transaction.
461
// If there is none, then the transaction has already gone.
462
// Otherwise do something with the transaction.
463

464             CoordinatorImpl coord =
465                 RecoveryManager.getLocalCoordinator(timeoutInfo.localTID);
466                                 
467             if (coord != null) {
468                 XID xid = new XID();
469                 xid.copy(coord.getGlobalTID());
470                 inDoubtList.addElement(xid);
471             }
472         }
473         
474         return (XID[]) inDoubtList.toArray(new XID[] {});
475        }
476     }
477
478     /**
479      * Returns the amount of time left before the given transaction times out.
480      *
481      * @param localTID The local identifier for the transaction.
482      *
483      * @return The time left. If there is no timeout for the transaction,
484      * this value will be negative. If the timeout period has been
485      * exceeded, this value will be zero.
486      *
487      * @see
488      */

489     static long timeLeft(Long JavaDoc localTID) {
490
491         TimeoutInfo timeoutInfo = (TimeoutInfo) pendingTimeouts.get(localTID);
492         if (timeoutInfo == null)
493             timeoutInfo = (TimeoutInfo) indoubtTimeouts.get(localTID);
494         long result = -1;
495         if (timeoutInfo != null) {
496             result = timeoutInfo.expireTime - new Date().getTime();
497             if (result < 0) {
498                 result = 0;
499             }
500         }
501
502         return result;
503     }
504
505     /**
506      * Informs the TimeoutManager that the transaction service
507      * is being shut down. For immediate shutdown, the timeout thread is
508      * stopped and all timeout information discarded.
509      *
510      * For quiesce, the timeout thread is stopped when there are no running
511      * transactions left.
512      *
513      * @param immediate Indicates whether to stop immediately.
514      *
515      * @return
516      *
517      * @see
518      */

519     static void shutdown(boolean immediate) {
520
521         // For immediate, kill the timeout thread and throw
522
// away all information. Also, if there are no pending
523
// timeouts, there is nothing to quiesce so
524
// shutdown immediately regardless.
525

526         if (immediate ||
527                 pendingTimeouts == null || pendingTimeouts.isEmpty()) {
528             if (timeoutThread != null) {
529                 timeoutThread.stop();
530             }
531
532             if (pendingTimeouts != null) {
533                 pendingTimeouts.clear();
534             }
535
536             pendingTimeouts = null;
537             timeoutThread = null;
538             timeoutActive = false;
539         } else {
540             quiescing = true;
541         }
542     }
543
544     /**
545      * Reports the contents of the TimeoutManager tables.
546      *$Only required for debug.
547      *
548      * @param immediate Indicates whether to stop immediately.
549      *
550      * @return
551      *
552      * @see
553      */

554     /*
555     static void report() {
556
557         // Report on pendingTimeouts.
558
559         if (pendingTimeouts.size() > 0) {
560             if(_logger.isLoggable(Level.FINER))
561             {
562                 _logger.logp(Level.FINER,"TimeoutManager","report()",
563                         "TimeoutManager.pendingTimeouts non-empty");
564             }
565             Enumeration keys = pendingTimeouts.keys();
566
567             while (keys.hasMoreElements()) {
568                 Long localTID = (Long) keys.nextElement();
569                 TimeoutInfo timeInfo =
570                     (TimeoutInfo) pendingTimeouts.get(localTID);
571                 if(_logger.isLoggable(Level.FINER))
572                 {
573                     _logger.logp(Level.FINER,"TimeoutManager","report()",
574                             "localTid :"+localTID+" -> " + timeInfo);
575                 }
576             }
577         } else {
578             if(_logger.isLoggable(Level.FINER))
579             {
580                 _logger.logp(Level.FINER,"TimeoutManager","report()",
581                         "TimeoutManager.pendingTimeouts empty");
582             }
583         }
584     }
585     */

586 }
587
588 /**
589  * This class records information for a timeout for a transaction.
590  *
591  * @version 0.1
592  *
593  * @author Simon Holdsworth, IBM Corporation
594  *
595  * @see
596  */

597
598 //----------------------------------------------------------------------------
599
// CHANGE HISTORY
600
//
601
// Version By Change Description
602
// 0.1 SAJH Initial implementation.
603
//----------------------------------------------------------------------------
604

605 class TimeoutInfo extends Object JavaDoc {
606     Long JavaDoc localTID = null;
607     long expireTime = 0;
608     int timeoutType = TimeoutManager.NO_TIMEOUT;
609 }
610
611 /**
612  * This class represents a thread on which the TimeoutManager can perform
613  * timeout checking.
614  *
615  * @version 0.01
616  *
617  * @author Simon Holdsworth, IBM Corporation
618  *
619  * @see
620  */

621
622 //----------------------------------------------------------------------------
623
// CHANGE HISTORY
624
//
625
// Version By Change Description
626
// 0.01 SAJH Initial implementation.
627
//----------------------------------------------------------------------------
628

629 class TimeoutThread extends Thread JavaDoc {
630
631     private int TIMEOUT_INTERVAL ;
632
633     static Logger JavaDoc _logger = LogDomains.getLogger(LogDomains.TRANSACTION_LOGGER);
634     /**
635      * TimeoutThread constructor.
636      * <p>
637      * This sets the thread name, and sets the thread to be a daemon thread so
638      * that it does not prevent the process from terminating.
639      *
640      * @param
641      *
642      * @return
643      *
644      * @see
645      */

646     TimeoutThread() {
647         setName("JTS Timeout Thread"/*#Frozen*/);
648         setDaemon(true);
649         try{
650             String JavaDoc timeout_interval = Configuration.getPropertyValue(Configuration.TIMEOUT_INTERVAL);
651             if(timeout_interval!=null){
652                 TIMEOUT_INTERVAL= Integer.parseInt(timeout_interval);
653         TIMEOUT_INTERVAL*=1000;
654                 if(TIMEOUT_INTERVAL<10000)
655                     TIMEOUT_INTERVAL=10000;
656             }
657             else{
658                 TIMEOUT_INTERVAL=10000;
659             }
660         }catch(Exception JavaDoc e){
661             TIMEOUT_INTERVAL=10000;
662         }
663     }
664
665     /**
666      * Performs timeout checking on a regular basis (every ten seconds or so).
667      *
668      * @param
669      *
670      * @return
671      *
672      * @see
673      */

674     public void run() {
675         try {
676             while (true) {
677
678                 // Sleep for a while between checks.
679

680                 Thread.sleep(TIMEOUT_INTERVAL);
681
682                 // Perform timeout checks, getting a list of timed-out
683
// transactions.
684

685                 Enumeration timedOut = TimeoutManager.checkTimeouts();
686
687                 // Now we must go through the list, telling each
688
// timed-out Coordinator to do something appropriate.
689

690                 if (timedOut != null) {
691                     while (timedOut.hasMoreElements()) {
692                         TimeoutInfo timeoutInfo =
693                             (TimeoutInfo) timedOut.nextElement();
694
695                         // Look up the Coordinator and tell it to roll back
696
// if it still exists. Note that we rely on the
697
// Coordinator calling removeCoordinator when it
698
// has finished, which will remove the timeout from
699
// the list, and remove other associations as well.
700

701                         TimeoutManager.
702                             timeoutCoordinator(timeoutInfo.localTID,
703                                                timeoutInfo.timeoutType);
704                     }
705                 }
706             }
707         } catch (InterruptedException JavaDoc exc) {
708             _logger.log(Level.INFO,"jts.time_out_thread_stopped");
709         }
710     }
711 }
712
Popular Tags