KickJava   Java API By Example, From Geeks To Geeks.

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


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: RecoveryManager.java
32
//
33
// Description: Process transaction management.
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 import java.io.*;
55
56 import org.omg.CORBA.*;
57 import org.omg.CosTransactions.*;
58
59 import com.sun.jts.jtsxa.*;
60
61 import javax.transaction.xa.*;
62 import com.sun.jts.jta.TransactionManagerImpl;
63
64 import com.sun.jts.trace.*;
65 import java.util.logging.Logger JavaDoc;
66 import java.util.logging.Level JavaDoc;
67 import com.sun.logging.LogDomains;
68 import com.sun.jts.utils.LogFormatter;
69 import com.sun.enterprise.autotxrecovery.TransactionRecovery;
70 /**
71  * This class manages information required for recovery, and also general
72  * state regarding transactions in a process.
73  *
74  * @version 0.01
75  *
76  * @author Simon Holdsworth, IBM Corporation
77  *
78  * @see
79 */

80
81 //----------------------------------------------------------------------------
82
// CHANGE HISTORY
83
//
84
// Version By Change Description
85
// 0.01 SAJH Initial implementation.
86
//-----------------------------------------------------------------------------
87

88 public class RecoveryManager {
89
90     /**
91      * list of XA Resources to be recovered.
92      */

93     private static Enumeration uniqueRMSet = null;
94
95     /**
96      * This attribute indicates whether initialisation has been started.
97      */

98     private static boolean initialised = false;
99
100     /**
101      * This attribute indicates the number of Coordinator objects which require
102      * resync. This is set to the number of in-doubt transactions recovered
103      * from the log, then decreased as transactions are resolved.
104      */

105     private static int resyncCoords = 0;
106
107     /**
108      * This attribute records the thread which is used to perform resync during
109      * restart
110      */

111     private static ResyncThread resyncThread = null;
112
113     /**
114      * This attribute is used to block new requests while there are
115      * Coordinators which still require resync.
116      */

117     private static EventSemaphore resyncInProgress = new EventSemaphore();
118
119     /**
120      * This attribute is used to block requests against RecoveryCoordinators or
121      * CoordinatorResources before recovery has completed.
122      */

123     private static EventSemaphore recoveryInProgress = new EventSemaphore();
124
125     /**
126      * This attribute is used by the Recovery Thread to know if the
127      * xaResource list is ready in case manual recovery is attempted.
128      */

129     private static EventSemaphore uniqueRMSetReady = new EventSemaphore();
130
131     private static Hashtable coordsByGlobalTID = new Hashtable();
132     private static Hashtable coordsByLocalTID = new Hashtable();
133
134     /**
135      * Mapping between transactionIds and threads. This is used to ensure
136      * there is at most one thread doing work in a transaction.
137      */

138     private static Hashtable transactionIds = new Hashtable();
139
140     /**
141      * Mapping between incompleteTxIds and their commit decisions.
142      */

143     private static Hashtable inCompleteTxMap = new Hashtable();
144
145     // This will start TransactionRecovery service as soon as all resources are available.
146
private static TransactionRecovery txRecovery;
147
148     
149     
150     /**
151      * This is intented to be used as a lock object.
152      */

153     private static java.lang.Object JavaDoc lockObject = new java.lang.Object JavaDoc();
154     /*
155         Logger to log transaction messages
156     */

157         static Logger JavaDoc _logger = LogDomains.getLogger(LogDomains.TRANSACTION_LOGGER);
158     /**
159      * Initialises the static state of the RecoveryManager class.
160      *
161      * @param
162      *
163      * @return
164      *
165      * @see
166      */

167     static void initialise() {
168
169         // If already initialised, return immediately.
170

171         if (initialised) {
172             return;
173         }
174
175         initialised = true;
176
177         // Perform recovery/resync if necessary.
178

179         if (Configuration.isRecoverable()) {
180             resyncThread = new ResyncThread();
181             if(_logger.isLoggable(Level.FINE))
182             {
183                 _logger.logp(Level.FINE,"RecoveryManager","initialise()",
184                         "Before starting ResyncThread ");
185             }
186             resyncThread.start();
187         } else {
188
189             // If the process is non-recoverable, but there is a valid server
190
// name,then check for a log file and issue a warning message
191
// if one exists. Also ensure that restart required is set to no.
192

193             if (!Configuration.isAppClientContainer()) {
194                 String JavaDoc serverName = Configuration.getServerName();
195                 if (serverName != null && Log.checkFileExists(serverName)) {
196                     _logger.log(Level.INFO,"jts.log_file_transient_server",serverName);
197
198                 }
199             }
200
201             // Modify the restart requirement in the repository, and
202
// post the event semaphore as there will be no Coordinators
203
// requiring resync.
204

205             try {
206                 recoveryInProgress.post(); // BUGFIX (Ram Jeyaraman)
207
resyncComplete(false, false);
208             } catch (Throwable JavaDoc exc) {}
209         }
210     }
211
212     /**
213      * Sets up the local and global identifier to Coordinator mapping as given.
214      * <p>
215      * If the global identifier has already got associated information,
216      * the operation returns false.
217      * <p>
218      * The timeout value, if non-zero, is used to establish a time-out for the
219      * transaction; if the local identifier to Coordinator association
220      * exists after the time-out period, then the TimeoutManager will
221      * attempt to roll the transaction back.
222      *
223      * @param globalTID The global identifier for the transaction.
224      * @param localTID The local identifier for the transaction.
225      * @param coord The Coordinator for the transaction.
226      * @param timeout The timeout for the transaction.
227      * @param log The log object for the transaction.
228      *
229      * @return Indicates success of the operation.
230      *
231      * @see
232      */

233     static boolean addCoordinator(GlobalTID globalTID,
234             Long JavaDoc localTID, CoordinatorImpl coord, int timeout) {
235
236         boolean result = true;
237
238         // Attempt to add the global and local indentifier to
239
// Coordinator associations to the maps.
240

241         coordsByGlobalTID.put(globalTID,coord);
242         coordsByLocalTID.put(localTID,coord);
243
244         // Set up the timeout for the transaction. When active, the
245
// timeout thread will periodically examine the map and abort
246
// any active transactions on it that have gone beyond their
247
// allocated time.
248

249         if (timeout != 0) {
250             TimeoutManager.setTimeout(localTID, TimeoutManager.ACTIVE_TIMEOUT,
251                                       timeout);
252         }
253
254         return result;
255     }
256
257     /**
258      * Removes the Coordinator associations for the given identifiers.
259      * <p>
260      * If there was no association the operation returns false.
261      * <p>
262      * Any timeout that was established for the Coordinator is cancelled,
263      * and any active thread associations for the transaction are removed
264      * and the corresponding Control objects destroyed.
265      *
266      * @param globalTID The global identifier for the transaction.
267      * @param localTID The local identifier for the transaction.
268      * @param aborted The transaction aborted indicator.
269      *
270      * @return Indicates success of the operation.
271      *
272      * @see
273      */

274     static boolean removeCoordinator(GlobalTID globalTID,
275             Long JavaDoc localTID, boolean aborted) {
276
277         boolean result = false;
278
279         // Remove the global identifier to Coordinator mapping if possible.
280

281         CoordinatorImpl coord = null;
282         result = (coordsByGlobalTID.remove(globalTID) != null);
283
284         // Remove the InternalTid to Coordinator mapping if possible.
285

286         if (result) {
287             coord = (CoordinatorImpl) coordsByLocalTID.remove(localTID);
288             result = (coord != null);
289         }
290
291         // If that succeeded, forget the CoordinatorLog object, if the
292
// transaction is not a subtransaction. The following may return
293
// FALSE if there are no log records available
294
// (i.e. non-recoverable OTS).
295

296         if (coord != null) {
297             try {
298                 if (coord.is_top_level_transaction()) {
299                     if (Configuration.isDBLoggingEnabled())
300                         LogDBHelper.getInstance().deleteRecord(localTID.longValue());
301                     else
302                         CoordinatorLog.removeLog(localTID);
303                 }
304             } catch(SystemException exc) {
305                 result = false;
306             }
307         }
308
309         // Clear the timeout for the transaction, if any.
310
// Perform the removal under the timer mutex.
311

312         TimeoutManager.setTimeout(localTID, TimeoutManager.CANCEL_TIMEOUT, 0);
313
314         // Modify any thread associations there may be for the transaction, to
315
// indicate that the transaction has ended.
316

317
318
319         // COMMENT(Ram J) 09/19/2001 This below line is commented out since in
320
// the J2EE controlled environment, all threads are associated and
321
// dissociated in an orderly fashion, as well as there is no possibility
322
// of concurrent threads active in a given transaction.
323
//CurrentTransaction.endAll(globalTID, aborted);
324

325         // If the count of resyncing Coordinators is greater than zero,
326
// this means we are still in resync. Decrease the count.
327

328         if (resyncCoords > 0) {
329
330             resyncCoords--;
331
332             // If the number of resyncing Coordinators is now zero,
333
// we may allow new work.
334

335             if (resyncCoords == 0) {
336                 try {
337                     resyncComplete(true, true);
338                 } catch (Throwable JavaDoc exc) {}
339             }
340         }
341
342         return result;
343     }
344
345     /**
346      * Returns a reference to the Coordinator object that corresponds to the
347      * global identifier passed as a parameter.
348      *
349      * @param globalTID The global identifier for the transaction.
350      *
351      * @return The Coordinator for the transaction.
352      *
353      * @see
354      */

355     static CoordinatorImpl getCoordinator(GlobalTID globalTID) {
356
357         CoordinatorImpl result = (CoordinatorImpl)
358             coordsByGlobalTID.get(globalTID);
359
360         return result;
361     }
362
363     /**
364      * Read and update the transaction ID map atomically with the current
365      * thread, if and only if there is no concurrent activity for the
366      * specified transaction id.
367      *
368      * @param tid transaction id.
369      *
370      * @return true if there is no concurrent activity and the map has been
371      * updated.
372      */

373     static boolean readAndUpdateTxMap(GlobalTID tid) {
374         synchronized (transactionIds) {
375             Thread JavaDoc thread = (Thread JavaDoc) transactionIds.get(tid);
376             if (thread != null) { // concurrent activity
377
return false;
378             }
379             // register the thread for the transaction id
380
transactionIds.put(tid, Thread.currentThread());
381             return true;
382         }
383     }
384
385     /**
386      * Get the value (thread) for the specified transaction id from the
387      * transaction ID map.
388      *
389      * @return the value for the transaction id key from the
390      * transaction ID map.
391      */

392     static Thread JavaDoc getThreadFromTxMap(GlobalTID tid) {
393         return (Thread JavaDoc) transactionIds.get(tid);
394     }
395
396     /**
397      * Remove the specified transaction id from the transaction ID map.
398      *
399      * @return the value for the transaction id key from the
400      * transaction ID map.
401      */

402     static Thread JavaDoc removeFromTxMap(GlobalTID tid) {
403         return (Thread JavaDoc) transactionIds.remove(tid);
404     }
405     
406     /**
407      * Requests that the RecoveryManager proceed with recovery.
408      * <p>
409      * The log is read and a list of TopCoordinators is reconstructed that
410      * corresponds to those transactions that were in-doubt at the time of the
411      * previous failure.
412      * <p>
413      * The method returns true if any transactions require resync.
414      *
415      * @param
416      *
417      * @return Indicates that there are Coordinators requiring resync.
418      *
419      * @see
420      */

421     static boolean recover() {
422
423         boolean result = false;
424
425         // Check the log for transactions. If there are any outstanding
426
// transactions, recover the Coordinator objects and set up the
427
// OMGtid to Coordinator map.
428

429         boolean keypointRequired = false;
430         Enumeration logRecords = CoordinatorLog.getLogged();
431
432         while (logRecords.hasMoreElements()) {
433             keypointRequired = true;
434             try {
435                 new TopCoordinator().
436                     reconstruct((CoordinatorLog) logRecords.nextElement());
437             } catch(Exception JavaDoc exc) {
438                 _logger.log(Level.SEVERE,"jts.recovery_in_doubt_exception",exc);
439                 _logger.log(Level.SEVERE,"jts.recovery_in_doubt",exc.toString());
440                  String JavaDoc msg = LogFormatter.getLocalizedMessage(_logger,
441                                             "jts.recovery_in_doubt",
442                                             new java.lang.Object JavaDoc[] {exc.toString()});
443                  throw new org.omg.CORBA.INTERNAL JavaDoc(msg);
444             }
445         }
446
447         // Perform recovery of XA resources.
448

449         //recoverXA();
450
if(_logger.isLoggable(Level.FINE))
451         {
452             _logger.logp(Level.FINE,"RecoveryManager","recover()",
453                     "Before invoking proceedWithXARecovery()");
454         }
455         proceedWithXARecovery();
456
457         // Post the recovery in progress event so that requests
458
// waiting for recovery to complete may proceed.
459

460         recoveryInProgress.post();
461
462         // If resync is not needed, then perform after-resync
463
// tasks immediately.
464

465         result = coordsByGlobalTID.size() > 0;
466         if (!result) {
467             try {
468                 resyncComplete(false,keypointRequired);
469             } catch(Throwable JavaDoc exc) {}
470         }
471
472         return result;
473     }
474
475     /**
476      * Performs resync processing.
477      * <p>
478      * The RecoveryManager gets recovery information from each TopCoordinator
479      * (while holding the transaction lock) and proceeds with resync.
480      * <p>
481      * Once resync is complete, a keypoint is taken to indicate that the log
482      * information is no longer required.
483      *
484      * @param
485      *
486      * @return
487      *
488      * @see
489      */

490     static void resync() {
491
492         // If there are any transactions, proceed with resync. The map of
493
// coordinators by global identifier is created during the
494
// TopCoordinator reconstruct method when the coordinators are added
495
// via addCoordinator. We copy the contents to another map as
496
// Coordinators will remove themselves from the map during resync.
497

498         // Now that the Coordinators have been reconstructed, record
499
// the number of transactions requiring resync,
500
// and make an event trace point. We must clone the Hashtable
501
// here so that the Enumeration does not get
502
// changed when any subsequent transaction is created (this can happen
503
// when the last Coordinator is removed).
504

505         resyncCoords = coordsByGlobalTID.size();
506         Enumeration resyncList =
507             ((Hashtable) coordsByGlobalTID.clone()).elements();
508
509         boolean isRoot[] = new boolean[1];
510
511         // Go through and resync each transaction. The transaction lock
512
// for each transaction is obtained to avoid deadlocks during recovery.
513

514         while (resyncList.hasMoreElements()) {
515
516             TopCoordinator coord = (TopCoordinator)resyncList.nextElement();
517
518             try {
519
520                 // Before performing recovery, lock the coordinator.
521

522                 synchronized (coord) {
523
524                     Status state = coord.recover(isRoot);
525
526                     if (state == Status.StatusUnknown) {
527
528                         // If the coordinator can be locked, then perform
529
// recovery on it. If the outcome is not currently
530
// known, we do nothing with the transaction,
531
// as we expect to eventually get an outcome
532
// from the parent. In this case an in-doubt timeout
533
// is established for the
534
// transaction so that it will continue to retry.
535
// For subordinates, the Coordinator will compl-ete the
536
// transaction itself as it will have no
537
// Synchronization objects.
538

539                         TimeoutManager.setTimeout(
540                             new Long JavaDoc(coord.getLocalTID()),
541                             TimeoutManager.IN_DOUBT_TIMEOUT,
542                             60);
543
544                     } else if (state == Status.StatusCommitted) {
545
546                         // For committed or rolled back, proceed with
547
// completion of the transaction, regardless of
548
// whether it is the root or a subordinate.
549
// If the transaction represents a root, it would
550
// normally wait for the CoordinatorTerm object to
551
// call before completing the transaction. As there is
552
// no CoordinatorTerm in recovery, we must do it here.
553
if(_logger.isLoggable(Level.FINE))
554                     {
555                         _logger.logp(Level.FINE,"RecoveryManager","resync()",
556                                 "Before invoking commit on the reconstructed coordinator"+
557                                 "GTID is: "+
558                                 ((TopCoordinator)coord).superInfo.globalTID.toString());
559                         
560                     }
561
562
563                         try {
564                             coord.commit();
565                         } catch (Throwable JavaDoc exc) {
566                             _logger.log(Level.WARNING,"jts.exception_during_resync",
567                                     new java.lang.Object JavaDoc[] {exc.toString(),"commit"});
568                         }
569
570                         if (isRoot[0]) {
571                             try {
572                                 coord.afterCompletion(state);
573                             } catch (Throwable JavaDoc exc) {
574                                 _logger.log(Level.WARNING,"jts.exception_during_resync",
575                                          new java.lang.Object JavaDoc[] {exc.toString(),
576                                          "after_completion"});
577                             }
578                         }
579
580                     } else {
581
582                         // By default, roll the transaction back.
583

584                         try {
585                             if(_logger.isLoggable(Level.FINE))
586                             {
587                                 _logger.logp(Level.FINE,"RecoveryManager","resync()",
588                                         "Before invoking rollback on the"+
589                                         "reconstructed coordinator :"+
590                                         "GTID is : "+
591                                         ((TopCoordinator)coord).superInfo.globalTID.toString());
592                             
593                             }
594                             coord.rollback(true);
595                         } catch (Throwable JavaDoc exc) {
596                             _logger.log(Level.WARNING,"jts.resync_failed",
597                                     new java.lang.Object JavaDoc [] {exc.toString(),"rollback"});
598                         }
599
600                         if (isRoot[0]) {
601                             try {
602                                 coord.afterCompletion(Status.StatusRolledBack);
603                             } catch (Throwable JavaDoc exc) {
604                                 _logger.log(Level.WARNING,"jts.resync_failed",
605                                         new java.lang.Object JavaDoc[]
606                                         { exc.toString(), "after_completion"});
607                             }
608                         }
609                     }
610                 }
611             } catch (Throwable JavaDoc exc) {}
612         }
613
614         // Note that resyncComplete will be called by the
615
// last TopCoordinator to complete resync (in removeCoordinator)
616
// so we do not need to do it here.
617
}
618
619     /**
620      * Called to indicate that resync is complete.
621      * <p>
622      * Indicates that all in-doubt Coordinators recovered from the log have
623      * obtained global outcomes are corresponding transactions are complete.
624      * <p>
625      * The parameters indicate whether there were Coordinators
626      * requiring resync, and whether a keypoint is required.
627      *
628      * @param resynced Indicates whether any resync was done.
629      * @param keypointRequired Indicates whether the log needs keypointing.
630      *
631      * @return
632      *
633      * @exception LogicErrorException An internal logic error occurred.
634      *
635      * @see
636      */

637     static void resyncComplete(boolean resynced,
638             boolean keypointRequired) throws LogicErrorException {
639
640         // Inform JTSXA that resync is complete, and trace the fact
641
// that resync has completed.
642

643         // COMMENT(Ram J) not needed anymore
644
//JTSXA.resyncComplete();
645

646         // Perform a keypoint of the log if required.
647

648         if (keypointRequired) {
649             CoordinatorLog.keypoint();
650         }
651
652         // Post the resync in progress event semaphore.
653

654         resyncInProgress.post();
655         resyncInProgress = null;
656     }
657
658     /**
659      * Returns a reference to the Coordinator object that corresponds to the
660      * local identifier passed as a parameter.
661      *
662      * @param localTID The local identifier for the transaction.
663      *
664      * @return The Coordinator object.
665      *
666      * @see
667      */

668     static CoordinatorImpl getLocalCoordinator(Long JavaDoc localTID) {
669
670         CoordinatorImpl result = (CoordinatorImpl)
671             coordsByLocalTID.get(localTID);
672
673         return result;
674     }
675
676     /**
677      * Determines whether the local transaction identifier represents a valid
678      * transaction.
679      *
680      * @param localTID The local transaction identifier to check.
681      *
682      * @return Indicates the local transaction identifier is valid.
683      *
684      * @see
685      */

686     static boolean validLocalTID(Long JavaDoc localTID) {
687
688         boolean result = coordsByLocalTID.containsKey(localTID);
689
690         return result;
691     }
692
693     /**
694      * Informs the RecoveryManager that the transaction service is being shut
695      * down.
696      *
697      * For immediate shutdown,
698      *
699      * For quiesce,
700      *
701      * @param immediate Indicates whether to stop immediately.
702      *
703      * @return
704      *
705      * @see
706      */

707     static void shutdown(boolean immediate) {
708
709
710         /**
711         if (immediate) {
712
713             // If immediate, stop the resync thread if any.
714
715             if (resyncThread != null) {
716                 resyncThread.stop();
717             }
718         } else {
719         **/

720
721             // Otherwise ensure that resync has completed.
722

723             if (resyncInProgress != null) {
724                 try {
725                     resyncInProgress.waitEvent();
726                     if (resyncThread != null) {
727                         resyncThread.join();
728                     }
729                 } catch (InterruptedException JavaDoc exc) {}
730             }
731         /**
732         }
733         **/

734
735         // COMMENT(Ram J) not needed anymore.
736
//JTSXA.shutdown(immediate);
737

738         // If not immediate shutdown, keypoint and close the log.
739
// Only do this if the process is recoverable!
740

741         if (!immediate && Configuration.isRecoverable()) {
742             CoordinatorLog.keypoint();
743             CoordinatorLog.finalizeAll();
744         }
745
746         //$Continue with shutdown/quiesce.
747
}
748
749     /**
750      * @param xid the xid to be stringified.
751      *
752      * @return stringified contents of the xid.
753      */

754     private static String JavaDoc stringifyXid(Xid xid) {
755         int glen = xid.getGlobalTransactionId().length;
756         int blen = xid.getBranchQualifier().length;
757         byte[] xidRep = new byte[glen + 1 + blen];
758
759         System.arraycopy(xid.getGlobalTransactionId(), 0, xidRep, 0, glen);
760         xidRep[glen] = (byte) ',';
761         System.arraycopy(xid.getBranchQualifier(), 0, xidRep, glen + 1, blen);
762
763         return new String JavaDoc(xidRep);
764     }
765
766     /**
767      * Reduce the set of XAResource objects into a unique set such that there
768      * is at most one XAResource object per RM.
769      */

770     private static Enumeration getUniqueRMSet(Enumeration xaResourceList){
771  
772         Vector uniqueRMList = new Vector();
773         
774         while (xaResourceList.hasMoreElements()) {
775             XAResource xaRes = (XAResource) xaResourceList.nextElement();
776             int size = uniqueRMList.size();
777             boolean match = false;
778             for (int i = 0; i < size; i++) { // compare and eliminate duplicates
779
XAResource uniqueXaRes = (XAResource) uniqueRMList.elementAt(i);
780                 try {
781                     if (xaRes.isSameRM(uniqueXaRes)) {
782                         match = true;
783                         break;
784                     }
785                 } catch (XAException xe) {}
786             }
787             if (!match) {
788                 uniqueRMList.add(xaRes);
789             }
790         }
791         
792         return uniqueRMList.elements();
793     }
794     
795     /**
796      * Recovers the in doubt transactions from the provided list of
797      * XAResource objects. This method is never called by the recovery
798      * thread, and its the application threads which wants to pass in
799      * the XA resources that call this.
800      *
801      * @param xaResources enumerated list of XA Resources to be recovered
802      *
803      */

804     public static void recoverXAResources(Enumeration xaResources) {
805
806         /* This method has been newly added - Ram Jeyaraman */
807
808         String JavaDoc manualRecovery =
809             Configuration.getPropertyValue(Configuration.MANUAL_RECOVERY);
810
811         // if ManualRecovery property is not set, do not attempt XA recovery.
812
if (manualRecovery == null ||
813                 !(manualRecovery.equalsIgnoreCase("true"/*#Frozen*/))) {
814             return;
815         }
816
817         synchronized (lockObject) {
818
819             if (uniqueRMSetReady.isPosted() == false) {
820                 RecoveryManager.uniqueRMSet = getUniqueRMSet(xaResources);
821                 uniqueRMSetReady.post();
822                 waitForResync();
823                 return;
824             } else {
825                 RecoveryManager.waitForResync();
826                 RecoveryManager.uniqueRMSet = getUniqueRMSet(xaResources);
827                 // the following call is meant to induce recovery. But
828
// currently it will not work as intended, if it is called
829
// during regular TP processing. Currently, this call deals
830
// only with XA recovery. There needs to be some support
831
// from the coordinator to be able to support recovery
832
// during TP processing.
833
proceedWithXARecovery();
834             }
835         }
836     }
837
838     /**
839      * This method returns InDoubt Xids for a given XAResource
840      */

841
842      static Xid[] getInDoubtXids(XAResource xaResource) {
843      if(_logger.isLoggable(Level.FINE))
844      {
845          _logger.logp(Level.FINE,"RecoveryManager", "getInDoubtXids()",
846           "Before receiving inDoubtXids from xaresource = " +
847           xaResource);
848          }
849          Xid[] inDoubtXids = null;
850          ArrayList inDoubtXidList = null;
851          int flags;
852          String JavaDoc recoveryScanFlags = System.getProperty("RECOVERSCANFLAGS");
853          if (recoveryScanFlags != null && recoveryScanFlags.equals("TMNOFLAGS"))
854              flags = XAResource.TMSTARTRSCAN;
855          else
856              flags = XAResource.TMSTARTRSCAN | XAResource.TMENDRSCAN;
857          boolean continueLoop = true;
858          while (continueLoop) {
859          try {
860                  inDoubtXids = xaResource.recover(flags);
861                  if (inDoubtXids == null || inDoubtXids.length == 0)
862                      break;
863                  if (flags == XAResource.TMSTARTRSCAN || flags == XAResource.TMNOFLAGS) {
864                       flags = XAResource.TMNOFLAGS;
865                       if (inDoubtXidList == null) {
866                           inDoubtXidList = new ArrayList();
867                       }
868                       for (int i = 0; i < inDoubtXids.length; i++)
869                           inDoubtXidList.add(inDoubtXids[i]);
870                  }
871                  else {
872                      break;
873                  }
874              } catch (XAException e) {
875             _logger.log(Level.WARNING,"jts.xaexception_in_recovery",e);
876                 break;
877              }
878
879          }
880          if (inDoubtXidList != null)
881              inDoubtXids = (Xid[])inDoubtXidList.toArray();
882      if(_logger.isLoggable(Level.FINE) && (inDoubtXids != null))
883      {
884          String JavaDoc xidList = LogFormatter.convertXidArrayToString(inDoubtXids);
885          _logger.logp(Level.FINE,"RecoveryManager",
886          "getInDoubtXid()",
887          "InDoubtXids returned from xaresource = "+
888           xaResource + "are: " +xidList);
889      }
890          return inDoubtXids;
891      }
892
893     /**
894      * This method is used to recontruct and register the Resource objects
895      * corresponding to in-doubt transactions in the RMs. It is assumed
896      * that the XAResource list has already been provided to the
897      * Recovery Manager. This method can be called by Recovery Thread as
898      * well as any other thread driving recovery of XA Resources.
899      */

900     private static void proceedWithXARecovery() {
901
902         /* This method has been newly added - Ram Jeyaraman */
903
904         Enumeration xaResources = RecoveryManager.uniqueRMSet;
905         String JavaDoc manualRecovery =
906             Configuration.getPropertyValue(Configuration.MANUAL_RECOVERY);
907
908         // if ManualRecovery property is not set, do not attempt XA recovery.
909
if (manualRecovery == null ||
910                 !(manualRecovery.equalsIgnoreCase("true"/*#Frozen*/))) {
911             return;
912         }
913
914         if (Thread.currentThread().getName().equals("JTS Resync Thread"/*#Frozen*/)) {
915
916             if (uniqueRMSetReady != null) {
917                 try {
918                     uniqueRMSetReady.waitEvent();
919                     txRecovery.start();
920                     txRecovery.raiseFence();
921                     xaResources = RecoveryManager.uniqueRMSet;
922                 } catch (InterruptedException JavaDoc exc) {
923                     _logger.log(Level.SEVERE,"jts.wait_for_resync_complete_interrupted");
924                      String JavaDoc msg = LogFormatter.getLocalizedMessage(_logger,
925                                                 "jts.wait_for_resync_complete_interrupted");
926                       throw new org.omg.CORBA.INTERNAL JavaDoc(msg);
927                 }
928             }
929         }
930
931         // sanity check
932
if (xaResources == null) {
933             return;
934         }
935
936         Vector otsResources = new Vector();
937         Map uniqueXids = new Hashtable();
938
939         while (xaResources.hasMoreElements()) {
940
941             XAResource xaResource = (XAResource) xaResources.nextElement();
942
943             // Get the list of XIDs which represent in-doubt transactions
944
// for the database.
945

946             Xid[] inDoubtXids = getInDoubtXids(xaResource);
947             uniqueXids.clear();
948             if (inDoubtXids == null || inDoubtXids.length == 0) {
949                     continue; // No in-doubt xids for this resource.
950
}
951
952             for (int i = 0; i < inDoubtXids.length; i++) {
953
954                     // check to see if the xid belongs to this server.
955

956                     String JavaDoc branchQualifier =
957                         new String JavaDoc(inDoubtXids[i].getBranchQualifier());
958                     String JavaDoc serverName = Configuration.getServerName();
959                     
960                     if (branchQualifier.startsWith(serverName)) {
961
962                         // check if the xid is a duplicate. i.e., Xids
963
// which have same globalId and branchId are
964
// considered duplicates. Note that the
965
// branchId format is (serverId, rmId). This is
966
// to make sure that at most one OTSResource object
967
// is registered with the coordinator per transaction
968
// per RM.
969

970                         String JavaDoc xidStr = stringifyXid(inDoubtXids[i]);
971                         if (uniqueXids.get(xidStr) == null) { // unique xid
972

973                             uniqueXids.put(xidStr, xidStr); // add to uniqueList
974

975                             // Create an OTSResource for the in-doubt
976
// transaction and add it to the list. Each
977
// OTSResource represents a RM per transaction.
978
otsResources.addElement(
979                                 new OTSResourceImpl(inDoubtXids[i],
980                                                     xaResource, null
981                                                    ).getCORBAObjReference());
982                         }
983                     }
984                 }
985         }
986
987
988         // For each OTSResource, determine whether the transaction is known,
989
// and if so, register it, otherwise roll it back.
990

991         for (int i = 0; i < otsResources.size(); i++) {
992
993             OTSResource otsResource = (OTSResource) otsResources.elementAt(i);
994             GlobalTID globalTID = new GlobalTID(otsResource.getGlobalTID());
995             TopCoordinator coord =
996                 (TopCoordinator) coordsByGlobalTID.get(globalTID);
997
998             if (coord == null) {
999                 // Roll the OTSResource back if the transaction is not
1000
// recognised. This happens when the RM has recorded its
1001
// prepare vote, but the JTS has not recorded its prepare vote.
1002
if(_logger.isLoggable(Level.FINE))
1003                {
1004                    _logger.logp(Level.FINE,"RecoveryManager","proceedWithXARecovery()",
1005                            "Could not recognize OTSResource: "+otsResource +
1006                            " with tid: " +
1007                            LogFormatter.convertToString(globalTID.realTID.tid)+
1008                            ";Hence rolling this resource back...");
1009                }
1010        
1011               boolean infiniteRetry = true;
1012               int commitRetries = Configuration.getRetries();
1013               if (commitRetries >= 0)
1014                   infiniteRetry = false;
1015               int commitRetriesLeft = commitRetries;
1016                boolean exceptionisThrown = true;
1017                while (exceptionisThrown) {
1018                    try {
1019                        otsResource.rollback();
1020                        exceptionisThrown = false;
1021                    } catch (Throwable JavaDoc exc) {
1022                        if ((exc instanceof COMM_FAILURE) || (exc instanceof TRANSIENT)) {
1023                            if (commitRetriesLeft > 0 || infiniteRetry) {
1024                                // For TRANSIENT or COMM_FAILURE, wait
1025
// for a while, then retry the commit.
1026
if (!infiniteRetry) {
1027                                    commitRetriesLeft--;
1028                                }
1029
1030                                try {
1031                                    Thread.sleep(Configuration.COMMIT_RETRY_WAIT);
1032                                } catch( Throwable JavaDoc e ) {}
1033                            }
1034                            else {
1035                               _logger.log(Level.WARNING,"jts.exception_during_resync",
1036                                        new java.lang.Object JavaDoc[] {exc.toString(),"OTSResource rollback"});
1037                               exceptionisThrown = false;
1038                            }
1039                        }
1040                        else {
1041                            _logger.log(Level.WARNING,"jts.exception_during_resync",
1042                                    new java.lang.Object JavaDoc[] {exc.toString(),"OTSResource rollback"});
1043                            exceptionisThrown = false;
1044                        }
1045                    }
1046                }
1047            } else {
1048                // NOTE: Currently unimplemented. The coordinator needs to
1049
// check if duplicate resources are being registered for the
1050
// same RM for the same xid. Also the coordinator should
1051
// not go away, until all its resources have been sent
1052
// completion notification. The keypointing should not
1053
// be done *as is* in the removeCoordinator() method.
1054
// waitForResync semaphore needs to be flagged when the
1055
// recovery thread goes away.
1056

1057                // Register the OTSResource with the Coordinator.
1058
// It will be called for commit or rollback during resync.
1059
if(_logger.isLoggable(Level.FINE))
1060                    {
1061                        _logger.logp(Level.FINE,"RecoveryManager",
1062                                "proceedWithXARecovery()",
1063                                "Recognized OTSResource: " + otsResource +
1064                                " with tid: " +
1065                                LogFormatter.convertToString(globalTID.realTID.tid) +
1066                                ";Hence registering this resource with coordinator...");
1067                    }
1068                     coord.directRegisterResource(otsResource);
1069            }
1070        }
1071    }
1072
1073    static void dbXARecovery() {
1074        Enumeration xaResources = RecoveryManager.uniqueRMSet;
1075        String JavaDoc manualRecovery =
1076            Configuration.getPropertyValue(Configuration.MANUAL_RECOVERY);
1077        // if ManualRecovery property is not set, do not attempt XA recovery.
1078
if (manualRecovery == null ||
1079                !(manualRecovery.equalsIgnoreCase("true"/*#Frozen*/))) {
1080            try {
1081            resyncComplete(false, false);
1082            } catch (Throwable JavaDoc ex) { }
1083            return;
1084        }
1085
1086        if (Thread.currentThread().getName().equals("JTS Resync Thread"/*#Frozen*/)) {
1087            if (uniqueRMSetReady != null) {
1088                try {
1089                    uniqueRMSetReady.waitEvent();
1090                    xaResources = RecoveryManager.uniqueRMSet;
1091                } catch (InterruptedException JavaDoc exc) {
1092            _logger.log(Level.SEVERE,"jts.wait_for_resync_complete_interrupted");
1093            String JavaDoc msg = LogFormatter.getLocalizedMessage(_logger,
1094                      "jts.wait_for_resync_complete_interrupted");
1095            throw new org.omg.CORBA.INTERNAL JavaDoc(msg);
1096                }
1097            }
1098        }
1099
1100        // sanity check
1101
if (xaResources == null) {
1102            try {
1103            resyncComplete(false, false);
1104            } catch (Throwable JavaDoc ex) { }
1105            return;
1106        }
1107
1108        // Get global TIDs
1109
Map gtidMap = LogDBHelper.getInstance().getGlobalTIDMap();
1110
1111        Map uniqueXids = new Hashtable();
1112
1113        while (xaResources.hasMoreElements()) {
1114
1115            XAResource xaResource = (XAResource) xaResources.nextElement();
1116
1117            // Get the list of XIDs which represent in-doubt transactions
1118
// for the database.
1119

1120            Xid[] inDoubtXids = getInDoubtXids(xaResource);
1121            uniqueXids.clear();
1122            if (inDoubtXids == null || inDoubtXids.length == 0) {
1123                    continue; // No in-doubt xids for this resource.
1124
}
1125            for (int i = 0; i < inDoubtXids.length; i++) {
1126
1127                    // check to see if the xid belongs to this server.
1128

1129                    String JavaDoc branchQualifier =
1130                        new String JavaDoc(inDoubtXids[i].getBranchQualifier());
1131                    String JavaDoc serverName = Configuration.getServerName();
1132                    
1133                    if (branchQualifier.startsWith(serverName)) {
1134
1135                        // check if the xid is a duplicate. i.e., Xids
1136
// which have same globalId and branchId are
1137
// considered duplicates. Note that the
1138
// branchId format is (serverId, rmId). This is
1139
// to make sure that at most one OTSResource object
1140
// is registered with the coordinator per transaction
1141
// per RM.
1142

1143                        String JavaDoc xidStr = stringifyXid(inDoubtXids[i]);
1144                        if (uniqueXids.get(xidStr) == null) { // unique xid
1145

1146                            uniqueXids.put(xidStr, xidStr); // add to uniqueList
1147

1148                            try {
1149                            byte[] gtrid = inDoubtXids[i].getGlobalTransactionId();
1150                            GlobalTID gtid = GlobalTID.fromTIDBytes(gtrid);
1151                            Long JavaDoc localTID = (Long JavaDoc)gtidMap.get(gtid);
1152                            if (localTID == null) {
1153                                 xaResource.rollback(inDoubtXids[i]);
1154                            } else {
1155                                 xaResource.commit(inDoubtXids[i], true);
1156                            }
1157                            LogDBHelper.getInstance().deleteRecord(localTID.longValue());
1158                            } catch (Exception JavaDoc ex) { ex.printStackTrace(); }
1159                        }
1160                    }
1161                }
1162        }
1163        try {
1164        resyncComplete(false, false);
1165        } catch (Throwable JavaDoc ex) { ex.printStackTrace(); }
1166    }
1167
1168
1169    /**
1170     * Requests that the RecoveryManager proceed with recovery of XA resources
1171     * via JTSXA.
1172     * <p>
1173     * JTSXA returns a list of OTSResource objects which require
1174     * outcomes. These are registered with appropriate Coordinators or rolled
1175     * back as appropriate.
1176     *
1177
1178
1179    /**
1180     * Requests that the RecoveryManager proceed with recovery of XA resources
1181     * via JTSXA.
1182     * <p>
1183     * JTSXA returns a list of OTSResource objects which require
1184     * outcomes. These are registered with appropriate Coordinators or rolled
1185     * back as appropriate.
1186     *
1187     * @param
1188     *
1189     * @return
1190     *
1191     * @see
1192     */

1193    /*
1194     * DISCARD(Ram J) - this method is not needed anymore. This has been
1195     * replaced by proceedWithXARecovery method.
1196     */

1197    /*
1198    private static void recoverXA() {
1199
1200        boolean result = false;
1201
1202        // Get a list of OTSResource objects from JTSXA.
1203
1204        Vector resources = new Vector();
1205        JTSXA.recover(resources);
1206        Enumeration res = resources.elements();
1207
1208        // For each OTSResource, determine whether the transaction is known,
1209        // and if so, register it, otherwise roll it back.
1210
1211        while (res.hasMoreElements()) {
1212
1213            TxOTSResource xares = (TxOTSResource) res.nextElement();
1214            GlobalTID globalTID = new GlobalTID(xares.getGlobalTID());
1215            TopCoordinator coord =
1216                (TopCoordinator) coordsByGlobalTID.get(globalTID);
1217
1218            // report();
1219
1220            if (coord == null) {
1221
1222                // Roll the OTSResource back if the transaction is not
1223                // recognised. This happens when the RM has recorded its
1224                // prepare vote, but the JTS has not recorded its prepare vote.
1225
1226                try {
1227                    xares.rollback();
1228                } catch (Throwable exc) {
1229                    _logger.log(Level.WARNING,"jts.exception_during_resync",
1230                            new java.lang.Object[] { exc.toString(), "xa_rollback"});
1231
1232
1233                }
1234            } else {
1235
1236                // Register the OTSResource with the Coordinator.
1237                // It will be called for commit or rollback during resync.
1238                coord.directRegisterResource(xares);
1239            }
1240        }
1241    }
1242    */

1243
1244    /**
1245     * Returns an array of Coordinator objects currently active.
1246     *
1247     * @param
1248     *
1249     * @return The array of Coordinators.
1250     *
1251     * @see
1252     */

1253    static CoordinatorImpl[] getCoordinators() {
1254
1255        int size = coordsByGlobalTID.size();
1256        CoordinatorImpl[] result = new CoordinatorImpl[size];
1257
1258        Enumeration coords = coordsByGlobalTID.elements();
1259
1260        for(int pos = 0;pos<size;){
1261            result[pos++] = (CoordinatorImpl) coords.nextElement();
1262        }
1263
1264        return result;
1265    }
1266
1267    static Hashtable/*<GlobalTID,Coordinator>*/ getCoordsByGlobalTID()
1268    {
1269        return coordsByGlobalTID;
1270    }
1271
1272
1273
1274    /**
1275     * Gets the restart data for the process.
1276     *
1277     * @param
1278     *
1279     * @return The restart data.
1280     *
1281     * @see
1282     */

1283    public static byte[] getRestart() {
1284
1285        byte[] result = null;
1286        LogFile logFile = Configuration.getLogFile();
1287        if (logFile != null)
1288          result = logFile.readRestart();
1289
1290        return result;
1291    }
1292
1293    /**
1294     * Sets the restart data for the process.
1295     *
1296     * @param bytes The restart data.
1297     *
1298     * @return
1299     *
1300     * @see
1301     */

1302    public static void setRestart(byte[] bytes) {
1303
1304        LogFile logFile = Configuration.getLogFile();
1305
1306        if (logFile != null) {
1307            if (!logFile.writeRestart(bytes)) {
1308                _logger.log(Level.WARNING,"jts.restart_write_failed");
1309            }
1310        }
1311    }
1312
1313    /**
1314     * Waits for recovery to complete.
1315     *
1316     * @param
1317     *
1318     * @return
1319     *
1320     * @see
1321     */

1322    public static void waitForRecovery() {
1323
1324        if (recoveryInProgress != null) {
1325            try {
1326                recoveryInProgress.waitEvent();
1327            } catch (InterruptedException JavaDoc exc) {
1328                _logger.log(Level.SEVERE,"jts.wait_for_resync_complete_interrupted");
1329                 String JavaDoc msg = LogFormatter.getLocalizedMessage(_logger,
1330                                            "jts.wait_for_resync_complete_interrupted");
1331                  throw new org.omg.CORBA.INTERNAL JavaDoc(msg);
1332            }
1333        }
1334    }
1335
1336    /**
1337     * Waits for resync to complete.
1338     *
1339     * @param
1340     *
1341     * @return
1342     *
1343     * @see
1344     */

1345    public static void waitForResync() {
1346
1347        if (resyncInProgress != null) {
1348            try {
1349                resyncInProgress.waitEvent();
1350            } catch (InterruptedException JavaDoc exc) {
1351                _logger.log(Level.SEVERE,"jts.wait_for_resync_complete_interrupted");
1352                 String JavaDoc msg = LogFormatter.getLocalizedMessage(_logger,
1353                                            "jts.wait_for_resync_complete_interrupted");
1354                  throw new org.omg.CORBA.INTERNAL JavaDoc(msg);
1355            }
1356        }
1357    }
1358    static void addToIncompleTx(CoordinatorImpl coord, boolean commit) {
1359        inCompleteTxMap.put(coord, new Boolean JavaDoc(commit));
1360    }
1361   
1362    public static void recoverIncompleteTx(XAResource[] xaresArray) {
1363        if ((xaresArray == null) || (xaresArray.length == 0))
1364            return;
1365        int size = xaresArray.length;
1366        Vector v = new Vector();
1367        for (int i=0; i<size; i++) {
1368            v.addElement(xaresArray[i]);
1369        }
1370        Enumeration resourceList = getUniqueRMSet(v.elements());
1371        Map uniqueXids = new Hashtable();
1372        Vector otsResources = new Vector();
1373        while (resourceList.hasMoreElements()) {
1374            XAResource xaResource = (XAResource) resourceList.nextElement();
1375            // Get the list of XIDs which represent in-doubt transactions
1376
// for the database.
1377
Xid[] inDoubtXids = getInDoubtXids(xaResource);
1378            uniqueXids.clear();
1379            if (inDoubtXids == null || inDoubtXids.length == 0) {
1380                continue; // No in-doubt xids for this resource.
1381
}
1382
1383            for (int i = 0; i < inDoubtXids.length; i++) {
1384
1385                    // check to see if the xid belongs to this server.
1386

1387                    String JavaDoc branchQualifier =
1388                        new String JavaDoc(inDoubtXids[i].getBranchQualifier());
1389                    String JavaDoc serverName = Configuration.getServerName();
1390
1391                    if (branchQualifier.startsWith(serverName)) {
1392
1393                        // check if the xid is a duplicate. i.e., Xids
1394
// which have same globalId and branchId are
1395
// considered duplicates. Note that the
1396
// branchId format is (serverId, rmId). This is
1397
// to make sure that at most one OTSResource object
1398
// is registered with the coordinator per transaction
1399
// per RM.
1400

1401                        String JavaDoc xidStr = stringifyXid(inDoubtXids[i]);
1402                        if (uniqueXids.get(xidStr) == null) { // unique xid
1403
uniqueXids.put(xidStr, xidStr); // add to uniqueList
1404
otsResources.addElement(
1405                                new OTSResourceImpl(inDoubtXids[i],
1406                                                    xaResource, null
1407                                                   ).getCORBAObjReference());
1408                        }
1409                    }
1410                }
1411            } // while (true)
1412
for (int i = 0; i < otsResources.size(); i++) {
1413                OTSResource otsResource = (OTSResource) otsResources.elementAt(i);
1414                GlobalTID globalTID = new GlobalTID(otsResource.getGlobalTID());
1415                synchronized (inCompleteTxMap) {
1416                    Enumeration e = inCompleteTxMap.keys();
1417                    while (e.hasMoreElements()) {
1418                        CoordinatorImpl cImpl = (CoordinatorImpl)e.nextElement();
1419                        GlobalTID gTID = new GlobalTID(cImpl.getGlobalTID());
1420                        if (gTID.equals(globalTID)) {
1421                            Boolean JavaDoc commit = (Boolean JavaDoc) inCompleteTxMap.get(cImpl);
1422                            boolean infiniteRetry = true;
1423                            int commitRetries = Configuration.getRetries();
1424                            if (commitRetries >= 0)
1425                                infiniteRetry = false;
1426                            int commitRetriesLeft = commitRetries;
1427                            boolean exceptionisThrown = true;
1428                            while (exceptionisThrown) {
1429                                try {
1430                                    if (commit.booleanValue()) {
1431                                        otsResource.commit();
1432                                    }
1433                                    else
1434                                        otsResource.rollback();
1435                                    exceptionisThrown = false;
1436                                } catch (Throwable JavaDoc exc) {
1437                                    if ((exc instanceof COMM_FAILURE) || (exc instanceof TRANSIENT)) {
1438                                        if (commitRetriesLeft > 0 || infiniteRetry) {
1439                                            // For TRANSIENT or COMM_FAILURE, wait
1440
// for a while, then retry the commit.
1441
if (!infiniteRetry) {
1442                                                commitRetriesLeft--;
1443                                            }
1444                                            try {
1445                                                Thread.sleep(Configuration.COMMIT_RETRY_WAIT);
1446                                            } catch( Throwable JavaDoc iex ) {}
1447                                        }
1448                                        else {
1449                                            _logger.log(Level.WARNING,"jts.exception_during_resync",
1450                                                        new java.lang.Object JavaDoc[] {exc.toString(),"OTSResource rollback"});
1451                                            exceptionisThrown = false;
1452                                        }
1453                                    }
1454                                    else {
1455                                        _logger.log(Level.WARNING,"jts.exception_during_resync",
1456                                                    new java.lang.Object JavaDoc[] {exc.toString(),"OTSResource rollback"});
1457                                        exceptionisThrown = false;
1458                                    }
1459                                }
1460                            }
1461                        }
1462                    }
1463                }
1464            }
1465    }
1466
1467    static void createRecoveryFile(String JavaDoc serverName) {
1468        try {
1469            int[] result = new int[1];
1470            String JavaDoc logPath = Configuration.getDirectory(Configuration.LOG_DIRECTORY,
1471                                                 Configuration.JTS_SUBDIRECTORY,
1472                                                 result);
1473            if( result[0] == Configuration.DEFAULT_USED ||
1474                result[0] == Configuration.DEFAULT_INVALID ) {
1475                if( result[0] == Configuration.DEFAULT_INVALID ) {
1476                    logPath = ".";
1477                }
1478            }
1479            File recoveryFile = LogControl.recoveryIdentifierFile(serverName,logPath);
1480            RandomAccessFile raf = new RandomAccessFile(recoveryFile,"rw");
1481            raf.writeBytes(serverName);
1482            raf.setLength(serverName.length());
1483            raf.close();
1484        } catch (Exception JavaDoc ex) {
1485            _logger.log(Level.WARNING,"jts.exception_in_recovery_file_handling",ex);
1486        }
1487    }
1488
1489    /**
1490     * Register the implementation of Automatice Transaction recovery.
1491     * This service is started as soon as all the resources are available.
1492     */

1493
1494    public static void registerTransactionRecoveryService(TransactionRecovery txRecoveryService) {
1495        txRecovery = txRecoveryService;
1496    }
1497
1498    /**
1499     * return the autoTxRecoveryObject
1500     */

1501    static TransactionRecovery getTransactionRecovery() {
1502        return txRecovery;
1503    }
1504
1505    
1506    /**
1507     * Reports the contents of the RecoveryManager tables.
1508     * $Only required for debug.
1509     *
1510     * @param immediate Indicates whether to stop immediately.
1511     *
1512     * @return
1513     *
1514     * @see
1515     */

1516    /*
1517    static void report() {
1518
1519        // Report on coordsByGlobalTID.
1520
1521        if (coordsByGlobalTID.size() > 0) {
1522            if(_logger.isLoggable(Level.FINE))
1523            {
1524                 _logger.logp(Level.FINE,"RecoveryManager","report()",
1525                        "RecoveryManager.coordsByGlobalTID non-empty");
1526            }
1527            Enumeration keys = coordsByGlobalTID.keys();
1528
1529            while (keys.hasMoreElements()) {
1530                GlobalTID globalTID = (GlobalTID) keys.nextElement();
1531                CoordinatorImpl coordImpl =
1532                    (CoordinatorImpl) coordsByGlobalTID.get(globalTID);
1533                if(_logger.isLoggable(Level.FINE))
1534                {
1535                    _logger.logp(Level.FINE,"RecoveryManager","report()",
1536                            "GlobalTid :"+globalTID+" -> "+coordImpl);
1537                }
1538            }
1539        } else {
1540                if(_logger.isLoggable(Level.FINE))
1541                {
1542                    _logger.logp(Level.FINE,"RecoveryManager","report()",
1543                            "RecoveryManager.coordsByGlobalTID empty");
1544                }
1545        }
1546
1547        // Report on coordsByLocalTID.
1548
1549        if (coordsByLocalTID.size() > 0) {
1550            if(_logger.isLoggable(Level.FINE))
1551            {
1552                _logger.logp(Level.FINE,"RecoveryManager","report()",
1553                        "RecoveryManager.coordsByLocalTID non-empty");
1554            }
1555            Enumeration keys = coordsByLocalTID.keys();
1556            while (keys.hasMoreElements()) {
1557                Long localTID = (Long)keys.nextElement();
1558                CoordinatorImpl coordImpl =
1559                    (CoordinatorImpl) coordsByLocalTID.get(localTID);
1560                if(_logger.isLoggable(Level.FINE))
1561                {
1562                    _logger.logp(Level.FINE,"RecoveryManager","report()",
1563                            "LocalTid:"+localTID+" -> " + coordImpl);
1564                }
1565            }
1566        } else {
1567            if(_logger.isLoggable(Level.FINE))
1568            {
1569                 _logger.logp(Level.FINE,"RecoveryManager","report()",
1570                        "RecoveryManager.coordsByLocalTID empty");
1571            }
1572        }
1573    }
1574    */

1575}
1576
1577/**
1578 * This class represents a thread on which the RecoveryManager can perform
1579 * resync operations.
1580 *
1581 * @version 0.01
1582 *
1583 * @author Simon Holdsworth, IBM Corporation
1584 *
1585 * @see
1586*/

1587
1588//----------------------------------------------------------------------------
1589
// CHANGE HISTORY
1590
//
1591
// Version By Change Description
1592
// 0.01 SAJH Initial implementation.
1593
//----------------------------------------------------------------------------
1594

1595class ResyncThread extends Thread JavaDoc {
1596
1597    /**
1598     * ResyncThread constructor.
1599     *
1600     * @param
1601     *
1602     * @return
1603     *
1604     * @see
1605     */

1606    static Logger JavaDoc _logger = LogDomains.getLogger(LogDomains.TRANSACTION_LOGGER);
1607
1608    ResyncThread() {
1609        setName("JTS Resync Thread"/*#Frozen*/);
1610        setDaemon(true);
1611    }
1612
1613    /**
1614     * Performs resync.
1615     *
1616     * @param
1617     *
1618     * @return
1619     *
1620     * @see
1621     */

1622    public void run() {
1623        yield();
1624
1625    if(_logger.isLoggable(Level.FINE))
1626    {
1627        _logger.logp(Level.FINE,"ResyncThread","run()","Before invoking RecoveryManager.recover()");
1628    }
1629        try {
1630            if (Configuration.isDBLoggingEnabled()) {
1631                RecoveryManager.dbXARecovery();
1632            } else {
1633                if (RecoveryManager.recover()) {
1634                    RecoveryManager.resync();
1635                }
1636            }
1637        } catch (Exception JavaDoc ex) {
1638            try {
1639                RecoveryManager.resyncComplete(false,false);
1640            } catch (Throwable JavaDoc tex) {tex.printStackTrace();} // forget any exeception in resyncComplete
1641
_logger.log(Level.SEVERE,"jts.log_exception_at_recovery",ex);
1642        }
1643        if(RecoveryManager.getTransactionRecovery() != null)
1644            RecoveryManager.getTransactionRecovery().lowerFence();
1645    }
1646}
1647
Popular Tags