KickJava   Java API By Example, From Geeks To Geeks.

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


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 import java.io.*;
33
34 import org.omg.CORBA.*;
35 import org.omg.CosTransactions.*;
36
37 import com.sun.jts.jtsxa.*;
38
39 import javax.transaction.xa.*;
40 import com.sun.jts.jta.TransactionManagerImpl;
41
42 import com.sun.jts.trace.*;
43 import java.util.logging.Logger JavaDoc;
44 import java.util.logging.Level JavaDoc;
45 import com.sun.logging.LogDomains;
46 import com.sun.jts.utils.LogFormatter;
47 /**
48  * This class manages information required for Delegated recovery. This class supports
49  * multiple delegated recoveries at the same time. Functionality is alsomost same as
50  * RecoveryManager.java. This class maintains the map between state and log location
51  * instead of static data incase of Recovery Manager.
52  *
53  * @version 0.01
54  *
55  * @author Sankara Rao Bhogi
56  *
57  * @see
58  */

59
60 public class DelegatedRecoveryManager {
61     
62     private static Hashtable recoveryStatetable = new Hashtable();
63     private static Hashtable tmoutMgrtable = new Hashtable();
64     
65     synchronized static DelegatedTimeoutManager getTimeoutManager(String JavaDoc logPath) {
66         DelegatedTimeoutManager tmoutMgr = (DelegatedTimeoutManager)tmoutMgrtable.get(logPath);
67         if (tmoutMgr != null)
68             return tmoutMgr;
69         tmoutMgr = new DelegatedTimeoutManager(logPath);
70         tmoutMgrtable.put(logPath,tmoutMgr);
71         return tmoutMgr;
72     }
73     
74     static Logger JavaDoc _logger = LogDomains.getLogger(LogDomains.TRANSACTION_LOGGER);
75     
76     static boolean addCoordinator(GlobalTID globalTID,
77     Long JavaDoc localTID, CoordinatorImpl coord, int timeout, String JavaDoc logPath) {
78         
79         
80         boolean result = true;
81         RecoveryStateHolder state = (RecoveryStateHolder)recoveryStatetable.get(logPath);
82         
83         // Attempt to add the global and local indentifier to
84
// Coordinator associations to the maps.
85

86         state.coordsByGlobalTID.put(globalTID,coord);
87         state.coordsByLocalTID.put(localTID,coord);
88         
89         // Set up the timeout for the transaction. When active, the
90
// timeout thread will periodically examine the map and abort
91
// any active transactions on it that have gone beyond their
92
// allocated time.
93

94         if (timeout != 0) {
95             DelegatedTimeoutManager tmoutMgr = getTimeoutManager(logPath);
96             tmoutMgr.setTimeout(localTID, DelegatedTimeoutManager.ACTIVE_TIMEOUT,
97             timeout);
98         }
99         
100         return result;
101     }
102     
103     static boolean removeCoordinator(GlobalTID globalTID,
104     Long JavaDoc localTID, boolean aborted, String JavaDoc logPath) {
105         
106         boolean result = false;
107         RecoveryStateHolder state = (RecoveryStateHolder)recoveryStatetable.get(logPath);
108         
109         // Remove the global identifier to Coordinator mapping if possible.
110

111         CoordinatorImpl coord = null;
112         result = (state.coordsByGlobalTID.remove(globalTID) != null);
113         
114         // Remove the InternalTid to Coordinator mapping if possible.
115

116         if (result) {
117             coord = (CoordinatorImpl) state.coordsByLocalTID.remove(localTID);
118             result = (coord != null);
119         }
120         
121         // If that succeeded, forget the CoordinatorLog object, if the
122
// transaction is not a subtransaction. The following may return
123
// FALSE if there are no log records available
124
// (i.e. non-recoverable OTS).
125

126         if (coord != null) {
127             try {
128                 if (coord.is_top_level_transaction()) {
129                     CoordinatorLog.removeLog(localTID, logPath);
130                 }
131             } catch(SystemException exc) {
132                 result = false;
133             }
134         }
135         
136         // Clear the timeout for the transaction, if any.
137
// Perform the removal under the timer mutex.
138

139         DelegatedTimeoutManager tmoutMgr = getTimeoutManager(logPath);
140         tmoutMgr.setTimeout(localTID, DelegatedTimeoutManager.CANCEL_TIMEOUT, 0);
141         
142         
143         
144         // Modify any thread associations there may be for the transaction, to
145
// indicate that the transaction has ended.
146

147         
148         
149         // COMMENT(Ram J) 09/19/2001 This below line is commented out since in
150
// the J2EE controlled environment, all threads are associated and
151
// dissociated in an orderly fashion, as well as there is no possibility
152
// of concurrent threads active in a given transaction.
153
//CurrentTransaction.endAll(globalTID, aborted);
154

155         // If the count of resyncing Coordinators is greater than zero,
156
// this means we are still in resync. Decrease the count.
157

158         if (state.resyncCoords > 0) {
159             
160             state.resyncCoords--;
161             
162             // If the number of resyncing Coordinators is now zero,
163
// we may allow new work.
164

165             if (state.resyncCoords == 0) {
166                 try {
167                     resyncComplete(true, true, logPath);
168                 } catch (Throwable JavaDoc exc) {}
169             }
170         }
171         
172         return result;
173     }
174     
175     
176     static CoordinatorImpl getCoordinator(GlobalTID globalTID, String JavaDoc logPath) {
177         
178         RecoveryStateHolder state = (RecoveryStateHolder)recoveryStatetable.get(logPath);
179         CoordinatorImpl result = (CoordinatorImpl)
180         state.coordsByGlobalTID.get(globalTID);
181         
182         return result;
183     }
184     
185     
186     public static boolean delegated_recover(String JavaDoc logPath, XAResource[] resources) throws Exception JavaDoc {
187        try {
188             File recoveryFile = new File(logPath,LogControl.RECOVERY_STRING_FILE_NAME);
189             RandomAccessFile raf = new RandomAccessFile(recoveryFile,"r");
190             long length = raf.length();
191             byte b1[] = new byte[(int)length]; // length is very small
192
raf.readFully(b1);
193             String JavaDoc serverName = new String JavaDoc(b1);
194             raf.close();
195             return delegated_recover(serverName,logPath,resources);
196        } catch (IOException ex) {
197            _logger.log(Level.WARNING,"jts.exception_in_recovery_file_handling",ex);
198            throw ex;
199            // return false;
200
}
201     }
202     public static boolean delegated_recover(String JavaDoc serverName, String JavaDoc logPath, XAResource[] resources) throws Exception JavaDoc {
203         if (logPath == null || serverName == null) {
204             return false;
205         }
206         Configuration.setServerName(logPath,serverName);
207         boolean result = false;
208         boolean keypointRequired = false;
209         RecoveryStateHolder state = new RecoveryStateHolder();
210         recoveryStatetable.put(logPath,state);
211         Enumeration logRecords = CoordinatorLog.getLogged(logPath);
212         while (logRecords.hasMoreElements()) {
213             keypointRequired = true;
214             try {
215                 (new TopCoordinator()).delegated_reconstruct((CoordinatorLog) logRecords.nextElement(), logPath);
216             } catch(Exception JavaDoc exc) {
217                 _logger.log(Level.SEVERE,"jts.recovery_in_doubt_exception",exc);
218                 _logger.log(Level.SEVERE,"jts.recovery_in_doubt",exc.toString());
219                 String JavaDoc msg = LogFormatter.getLocalizedMessage(_logger, "jts.recovery_in_doubt",
220                 new java.lang.Object JavaDoc[] {exc.toString()});
221                 throw new org.omg.CORBA.INTERNAL JavaDoc(msg);
222             }
223         }
224         
225         
226         int size = resources.length;
227         Vector v = new Vector();
228         for (int i=0; i<size; i++) {
229             v.addElement(resources[i]);
230         }
231         state.uniqueRMSet = getUniqueRMSet(v.elements());
232         proceedWithXARecovery(logPath);
233         state.recoveryInProgress.post();
234         
235         // If resync is not needed, then perform after-resync
236
// tasks immediately.
237

238         result = state.coordsByGlobalTID.size() > 0;
239         if (!result) {
240             try {
241                 resyncComplete(false,keypointRequired,logPath);
242             } catch(Throwable JavaDoc exc) {}
243         }
244         
245         if (result)
246             resync(logPath);
247         return true;
248     }
249     
250     static void resync(String JavaDoc logPath) {
251         
252         // If there are any transactions, proceed with resync. The map of
253
// coordinators by global identifier is created during the
254
// TopCoordinator reconstruct method when the coordinators are added
255
// via addCoordinator. We copy the contents to another map as
256
// Coordinators will remove themselves from the map during resync.
257

258         // Now that the Coordinators have been reconstructed, record
259
// the number of transactions requiring resync,
260
// and make an event trace point. We must clone the Hashtable
261
// here so that the Enumeration does not get
262
// changed when any subsequent transaction is created (this can happen
263
// when the last Coordinator is removed).
264

265         RecoveryStateHolder recoveryState = (RecoveryStateHolder)recoveryStatetable.get(logPath);
266         
267         recoveryState.resyncCoords = recoveryState.coordsByGlobalTID.size();
268         Enumeration resyncList =
269         ((Hashtable) recoveryState.coordsByGlobalTID.clone()).elements();
270         
271         boolean isRoot[] = new boolean[1];
272         
273         // Go through and resync each transaction. The transaction lock
274
// for each transaction is obtained to avoid deadlocks during recovery.
275

276         while (resyncList.hasMoreElements()) {
277             
278             TopCoordinator coord = (TopCoordinator)resyncList.nextElement();
279             
280             try {
281                 
282                 // Before performing recovery, lock the coordinator.
283

284                 synchronized (coord) {
285                     
286                     Status state = coord.recover(isRoot);
287                     
288                     if (state == Status.StatusUnknown) {
289                         
290                         // If the coordinator can be locked, then perform
291
// recovery on it. If the outcome is not currently
292
// known, we do nothing with the transaction,
293
// as we expect to eventually get an outcome
294
// from the parent. In this case an in-doubt timeout
295
// is established for the
296
// transaction so that it will continue to retry.
297
// For subordinates, the Coordinator will compl-ete the
298
// transaction itself as it will have no
299
// Synchronization objects.
300

301                         DelegatedTimeoutManager tmoutMgr = getTimeoutManager(logPath);
302                         tmoutMgr.setTimeout(
303                         new Long JavaDoc(coord.getLocalTID()),
304                         DelegatedTimeoutManager.IN_DOUBT_TIMEOUT,
305                         60);
306                         
307                     } else if (state == Status.StatusCommitted) {
308                         
309                         // For committed or rolled back, proceed with
310
// completion of the transaction, regardless of
311
// whether it is the root or a subordinate.
312
// If the transaction represents a root, it would
313
// normally wait for the CoordinatorTerm object to
314
// call before completing the transaction. As there is
315
// no CoordinatorTerm in recovery, we must do it here.
316
if(_logger.isLoggable(Level.FINE)) {
317                             _logger.logp(Level.FINE,"DelegatedRecoveryManager","resync()",
318                             "Before invoking commit on the reconstructed coordinator"+
319                             "GTID is: "+
320                             ((TopCoordinator)coord).superInfo.globalTID.toString());
321                             
322                         }
323                         
324                         
325                         try {
326                             coord.commit();
327                         } catch (Throwable JavaDoc exc) {
328                             _logger.log(Level.WARNING,"jts.exception_during_resync",
329                             new java.lang.Object JavaDoc[] {exc.toString(),"commit"});
330                         }
331                         
332                         if (isRoot[0]) {
333                             try {
334                                 coord.afterCompletion(state);
335                             } catch (Throwable JavaDoc exc) {
336                                 _logger.log(Level.WARNING,"jts.exception_during_resync",
337                                 new java.lang.Object JavaDoc[] {exc.toString(),
338                                 "after_completion"});
339                             }
340                         }
341                         
342                     } else {
343                         
344                         // By default, roll the transaction back.
345

346                         try {
347                             if(_logger.isLoggable(Level.FINE)) {
348                                 _logger.logp(Level.FINE,"DelegatedRecoveryManager","resync()",
349                                 "Before invoking rollback on the"+
350                                 "reconstructed coordinator :"+
351                                 "GTID is : "+
352                                 ((TopCoordinator)coord).superInfo.globalTID.toString());
353                                 
354                             }
355                             coord.rollback(true);
356                         } catch (Throwable JavaDoc exc) {
357                             _logger.log(Level.WARNING,"jts.resync_failed",
358                             new java.lang.Object JavaDoc [] {exc.toString(),"rollback"});
359                         }
360                         
361                         if (isRoot[0]) {
362                             try {
363                                 coord.afterCompletion(Status.StatusRolledBack);
364                             } catch (Throwable JavaDoc exc) {
365                                 _logger.log(Level.WARNING,"jts.resync_failed",
366                                 new java.lang.Object JavaDoc[]
367                                 { exc.toString(), "after_completion"});
368                             }
369                         }
370                     }
371                 }
372             } catch (Throwable JavaDoc exc) {}
373         }
374         
375         // Note that resyncComplete will be called by the
376
// last TopCoordinator to complete resync (in removeCoordinator)
377
// so we do not need to do it here.
378
}
379     
380     
381     private static void resyncComplete(boolean resynced,
382     boolean keypointRequired, String JavaDoc logPath) throws LogicErrorException {
383         
384         RecoveryStateHolder state = (RecoveryStateHolder)recoveryStatetable.get(logPath);
385         // Inform JTSXA that resync is complete, and trace the fact
386
// that resync has completed.
387

388         // COMMENT(Ram J) not needed anymore
389
//JTSXA.resyncComplete();
390

391         // Perform a keypoint of the log if required.
392

393         if (keypointRequired) {
394             CoordinatorLog.keypoint(logPath);
395         }
396         
397         // Post the resync in progress event semaphore.
398

399         state.resyncInProgress.post();
400         state.resyncInProgress = null;
401     }
402     
403     /**
404      * Returns a reference to the Coordinator object that corresponds to the
405      * local identifier passed as a parameter.
406      *
407      * @param localTID The local identifier for the transaction.
408      *
409      * @param logPath log location for which the delegated recovery is done
410      *
411      * @return The Coordinator object.
412      *
413      * @see
414      */

415     
416     static CoordinatorImpl getLocalCoordinator(Long JavaDoc localTID, String JavaDoc logPath) {
417         
418         RecoveryStateHolder state = (RecoveryStateHolder)recoveryStatetable.get(logPath);
419         CoordinatorImpl result = (CoordinatorImpl)
420         state.coordsByLocalTID.get(localTID);
421         
422         return result;
423     }
424     
425     /**
426      * Determines whether the local transaction identifier represents a valid
427      * transaction.
428      *
429      * @param localTID The local transaction identifier to check.
430      *
431      * @param logPath log location for which the delegated recovery is done
432      *
433      * @return Indicates the local transaction identifier is valid.
434      *
435      * @see
436      */

437     
438     static boolean validLocalTID(Long JavaDoc localTID, String JavaDoc logPath) {
439         RecoveryStateHolder state = (RecoveryStateHolder)recoveryStatetable.get(logPath);
440         
441         boolean result = state.coordsByLocalTID.containsKey(localTID);
442         
443         return result;
444     }
445     
446     /**
447      * Informs the DelegatedRecoveryManager that the transaction service is being shut
448      * down.
449      *
450      * For immediate shutdown,
451      *
452      * For quiesce,
453      *
454      * @param immediate Indicates whether to stop immediately.
455      *
456      * @return
457      *
458      * @see
459      */

460     static void shutdown(boolean immediate) {
461         
462         
463         Enumeration keys = recoveryStatetable.keys();
464         if (keys.hasMoreElements()) {
465             String JavaDoc logPath = (String JavaDoc)keys.nextElement();
466             RecoveryStateHolder state = (RecoveryStateHolder)recoveryStatetable.get(logPath);
467             if (immediate) {
468                 // If immediate, stop the resync thread if any.
469

470             } else {
471                 
472                 // Otherwise ensure that resync has completed.
473

474                 if (state.resyncInProgress != null) {
475                     try {
476                         state.resyncInProgress.waitEvent();
477                     } catch (InterruptedException JavaDoc exc) {}
478                 }
479             }
480             
481             // COMMENT(Ram J) not needed anymore.
482
//JTSXA.shutdown(immediate);
483

484             // If not immediate shutdown, keypoint and close the log.
485
// Only do this if the process is recoverable!
486

487             if (!immediate) {
488                 CoordinatorLog.keypoint(logPath);
489                 CoordinatorLog.finalizeAll(logPath);
490             }
491             
492             //$Continue with shutdown/quiesce.
493
}
494     }
495     
496     /**
497      * @param xid the xid to be stringified.
498      *
499      * @return stringified contents of the xid.
500      */

501     private static String JavaDoc stringifyXid(Xid xid) {
502         int glen = xid.getGlobalTransactionId().length;
503         int blen = xid.getBranchQualifier().length;
504         byte[] xidRep = new byte[glen + 1 + blen];
505         
506         System.arraycopy(xid.getGlobalTransactionId(), 0, xidRep, 0, glen);
507         xidRep[glen] = (byte) ',';
508         System.arraycopy(xid.getBranchQualifier(), 0, xidRep, glen + 1, blen);
509         
510         return new String JavaDoc(xidRep);
511     }
512     
513     /**
514      * Reduce the set of XAResource objects into a unique set such that there
515      * is at most one XAResource object per RM.
516      */

517     private static Enumeration getUniqueRMSet(Enumeration xaResourceList){
518         
519         Vector uniqueRMList = new Vector();
520         
521         while (xaResourceList.hasMoreElements()) {
522             XAResource xaRes = (XAResource) xaResourceList.nextElement();
523             int size = uniqueRMList.size();
524             boolean match = false;
525             for (int i = 0; i < size; i++) { // compare and eliminate duplicates
526
XAResource uniqueXaRes = (XAResource) uniqueRMList.elementAt(i);
527                 try {
528                     if (xaRes.isSameRM(uniqueXaRes)) {
529                         match = true;
530                         break;
531                     }
532                 } catch (XAException xe) {}
533             }
534             if (!match) {
535                 uniqueRMList.add(xaRes);
536             }
537         }
538         
539         return uniqueRMList.elements();
540     }
541     
542     
543     /**
544      * This method is used to recontruct and register the Resource objects
545      * corresponding to in-doubt transactions in the RMs. It is assumed
546      * that the XAResource list has already been provided to the
547      * Recovery Manager. This method can be called by Recovery Thread as
548      * well as any other thread driving recovery of XA Resources.
549      */

550     private static void proceedWithXARecovery(String JavaDoc logPath) {
551         
552         RecoveryStateHolder state = (RecoveryStateHolder)recoveryStatetable.get(logPath);
553         
554         /* This method has been newly added - Ram Jeyaraman */
555         
556         Enumeration xaResources = state.uniqueRMSet;
557         
558         // sanity check
559
if (xaResources == null) {
560             return;
561         }
562         
563         Vector otsResources = new Vector();
564         Map uniqueXids = new Hashtable();
565         
566         while (xaResources.hasMoreElements()) {
567             
568             XAResource xaResource = (XAResource) xaResources.nextElement();
569             
570             // Get the list of XIDs which represent in-doubt transactions
571
// for the database.
572

573             Xid[] inDoubtXids = RecoveryManager.getInDoubtXids(xaResource);
574             uniqueXids.clear();
575                 if (inDoubtXids == null || inDoubtXids.length == 0) {
576                     break; // all in-doubt xids have been obtained.
577
}
578                 
579                 for (int i = 0; i < inDoubtXids.length; i++) {
580                     
581                     // check to see if the xid belongs to this server.
582

583                     String JavaDoc branchQualifier =
584                     new String JavaDoc(inDoubtXids[i].getBranchQualifier());
585                     String JavaDoc serverName = Configuration.getServerName(logPath);
586                     
587                     if (branchQualifier.startsWith(serverName)) {
588                         
589                         // check if the xid is a duplicate. i.e., Xids
590
// which have same globalId and branchId are
591
// considered duplicates. Note that the
592
// branchId format is (serverId, rmId). This is
593
// to make sure that at most one OTSResource object
594
// is registered with the coordinator per transaction
595
// per RM.
596

597                         String JavaDoc xidStr = stringifyXid(inDoubtXids[i]);
598                         if (uniqueXids.get(xidStr) == null) { // unique xid
599

600                             uniqueXids.put(xidStr, xidStr); // add to uniqueList
601

602                             // Create an OTSResource for the in-doubt
603
// transaction and add it to the list. Each
604
// OTSResource represents a RM per transaction.
605
otsResources.addElement(
606                             new OTSResourceImpl(inDoubtXids[i],
607                             xaResource, null
608                             ).getCORBAObjReference());
609                         }
610                     }
611                 }
612             }
613         
614         // For each OTSResource, determine whether the transaction is known,
615
// and if so, register it, otherwise roll it back.
616

617         for (int i = 0; i < otsResources.size(); i++) {
618             
619             OTSResource otsResource = (OTSResource) otsResources.elementAt(i);
620             GlobalTID globalTID = new GlobalTID(otsResource.getGlobalTID());
621             TopCoordinator coord =
622             (TopCoordinator) state.coordsByGlobalTID.get(globalTID);
623             
624             if (coord == null) {
625                 // Roll the OTSResource back if the transaction is not
626
// recognised. This happens when the RM has recorded its
627
// prepare vote, but the JTS has not recorded its prepare vote.
628
if(_logger.isLoggable(Level.FINE)) {
629                     _logger.logp(Level.FINE,"DelegatedRecoveryManager","proceedWithXARecovery()",
630                     "Could not recognize OTSResource: "+otsResource +
631                     " with tid: " +
632                     LogFormatter.convertToString(globalTID.realTID.tid)+
633                     ";Hence rolling this resource back...");
634                 }
635                 boolean infiniteRetry = true;
636                 int commitRetries = Configuration.getRetries();
637                 if (commitRetries >= 0)
638                     infiniteRetry = false;
639                 int commitRetriesLeft = commitRetries;
640                 boolean exceptionisThrown = true;
641                 while (exceptionisThrown) {
642                     try {
643                         otsResource.rollback();
644                         exceptionisThrown = false;
645                     } catch (Throwable JavaDoc exc) {
646                         if ((exc instanceof COMM_FAILURE) || (exc instanceof TRANSIENT)) {
647                             if (commitRetriesLeft > 0 || infiniteRetry) {
648                                 // For TRANSIENT or COMM_FAILURE, wait
649
// for a while, then retry the commit.
650
if (!infiniteRetry) {
651                                     commitRetriesLeft--;
652                                 }
653                                 
654                                 try {
655                                     Thread.sleep(Configuration.COMMIT_RETRY_WAIT);
656                                 } catch( Throwable JavaDoc e ) {}
657                             }
658                             else {
659                                 _logger.log(Level.WARNING,"jts.exception_during_resync",
660                                 new java.lang.Object JavaDoc[] {exc.toString(),"OTSResource rollback"});
661                                 exceptionisThrown = false;
662                             }
663                         }
664                         else {
665                             _logger.log(Level.WARNING,"jts.exception_during_resync",
666                             new java.lang.Object JavaDoc[] {exc.toString(),"OTSResource rollback"});
667                             exceptionisThrown = false;
668                         }
669                     }
670                 }
671             } else {
672                 // NOTE: Currently unimplemented. The coordinator needs to
673
// check if duplicate resources are being registered for the
674
// same RM for the same xid. Also the coordinator should
675
// not go away, until all its resources have been sent
676
// completion notification. The keypointing should not
677
// be done *as is* in the removeCoordinator() method.
678
// waitForResync semaphore needs to be flagged when the
679
// recovery thread goes away.
680

681                 // Register the OTSResource with the Coordinator.
682
// It will be called for commit or rollback during resync.
683
if(_logger.isLoggable(Level.FINE)) {
684                     _logger.logp(Level.FINE,"DelegatedRecoveryManager",
685                     "proceedWithXARecovery()",
686                     "Recognized OTSResource: " + otsResource +
687                     " with tid: " +
688                     LogFormatter.convertToString(globalTID.realTID.tid) +
689                     ";Hence registering this resource with coordinator...");
690                 }
691                 coord.directRegisterResource(otsResource);
692             }
693         }
694     }
695     
696     
697     /**
698      * Returns an array of Coordinator objects currently active.
699      *
700      * @param logPath log location for which the delegated recovery is done
701      *
702      * @return The array of Coordinators.
703      *
704      * @see
705      */

706     static CoordinatorImpl[] getCoordinators(String JavaDoc logPath) {
707         
708         RecoveryStateHolder state = (RecoveryStateHolder)recoveryStatetable.get(logPath);
709         int size = state.coordsByGlobalTID.size();
710         CoordinatorImpl[] result = new CoordinatorImpl[size];
711         
712         Enumeration coords = state.coordsByGlobalTID.elements();
713         
714         for(int pos = 0;pos<size;){
715             result[pos++] = (CoordinatorImpl) coords.nextElement();
716         }
717         
718         return result;
719     }
720     
721     
722     static Hashtable/*<GlobalTID,Coordinator>*/ getCoordsByGlobalTID(String JavaDoc logPath) {
723         RecoveryStateHolder state = (RecoveryStateHolder)recoveryStatetable.get(logPath);
724         return state.coordsByGlobalTID;
725     }
726     
727     
728     
729     public static void waitForRecovery(String JavaDoc logPath) {
730         RecoveryStateHolder state = (RecoveryStateHolder)recoveryStatetable.get(logPath);
731         
732         if (state.recoveryInProgress != null) {
733             try {
734                 state.recoveryInProgress.waitEvent();
735             } catch (InterruptedException JavaDoc exc) {
736                 _logger.log(Level.SEVERE,"jts.wait_for_resync_complete_interrupted");
737                 String JavaDoc msg = LogFormatter.getLocalizedMessage(_logger,
738                 "jts.wait_for_resync_complete_interrupted");
739                 throw new org.omg.CORBA.INTERNAL JavaDoc(msg);
740             }
741         }
742     }
743     
744     /**
745      * Waits for resync to complete.
746      *
747      * @param logPath log location for which the delegated recovery is done
748      *
749      * @return
750      *
751      * @see
752      */

753     public static void waitForResync(String JavaDoc logPath) {
754         RecoveryStateHolder state = (RecoveryStateHolder)recoveryStatetable.get(logPath);
755         if (state.resyncInProgress != null) {
756             try {
757                 state.resyncInProgress.waitEvent();
758             } catch (InterruptedException JavaDoc exc) {
759                 _logger.log(Level.SEVERE,"jts.wait_for_resync_complete_interrupted");
760                 String JavaDoc msg = LogFormatter.getLocalizedMessage(_logger,
761                 "jts.wait_for_resync_complete_interrupted");
762                 throw new org.omg.CORBA.INTERNAL JavaDoc(msg);
763             }
764         }
765     }
766     
767 }
768
769 class RecoveryStateHolder {
770     
771     /**
772      * list of XA Resources to be recovered.
773      */

774     Enumeration uniqueRMSet = null;
775     
776     /**
777      * This attribute indicates the number of Coordinator objects which require
778      * resync. This is set to the number of in-doubt transactions recovered
779      * from the log, then decreased as transactions are resolved.
780      */

781     int resyncCoords = 0;
782     
783     /**
784      * This attribute is used to block new requests while there are
785      * Coordinators which still require resync.
786      */

787     EventSemaphore resyncInProgress = new EventSemaphore();
788     
789     /**
790      * This attribute is used to block requests against RecoveryCoordinators or
791      * CoordinatorResources before recovery has completed.
792      */

793     EventSemaphore recoveryInProgress = new EventSemaphore();
794     
795     Hashtable coordsByGlobalTID = new Hashtable();
796     Hashtable coordsByLocalTID = new Hashtable();
797     Hashtable transactionIds = new Hashtable();
798 }
799
Popular Tags