KickJava   Java API By Example, From Geeks To Geeks.

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


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: RecoveryCoordinatorImpl.java
32
//
33
// Description: Transaction RecoveryCoordinator object implementation.
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 org.omg.CORBA.*;
54 import org.omg.PortableServer.*;
55 import org.omg.CosTransactions.*;
56 import com.sun.jts.trace.*;
57 import java.util.logging.Logger JavaDoc;
58 import java.util.logging.Level JavaDoc;
59 import com.sun.logging.LogDomains;
60 import com.sun.jts.utils.LogFormatter;
61
62 /**
63  * The RecoveryCoordinatorImpl interface is our implementation of the standard
64  * RecoveryCoordinator interface. It allows recoverable objects to drive the
65  * recovery process in certain situations. Each instance of this class is
66  * implicitly associated with a single resource registration, and may only be
67  * used by that resource in that particular transaction for which it is
68  * registered. An instance of this class should be accessed from only one
69  * thread within a process.
70  *
71  * @version 0.02
72  *
73  * @author Simon Holdsworth, IBM Corporation
74  *
75  * @see
76  */

77
78 //----------------------------------------------------------------------------
79
// CHANGE HISTORY
80
//
81
// Version By Change Description
82
// 0.01 SAJH Initial implementation.
83
// 0.02 GDH Gordon Hutchison April 1998
84
// Added in COMMITTING to replay_completion
85
//-----------------------------------------------------------------------------
86

87 class RecoveryCoordinatorImpl extends RecoveryCoordinatorPOA {
88
89     private static boolean recoverable = false;
90     private static POA poa = null;
91     private RecoveryCoordinator thisRef = null;
92     private int internalSeq = 0;
93     /*
94         Logger to log transaction messages
95     */

96     static Logger JavaDoc _logger = LogDomains.getLogger(LogDomains.TRANSACTION_LOGGER);
97     GlobalTID globalTID = null;
98
99     RecoveryCoordinatorImpl() {}
100
101     /**
102      * Sets up the RecoveryCoordinator with the global identifier.
103      * <p>
104      * This is so that it can always find the Coordinator to inform it of the
105      * requirement for recovery of the given Resource.
106      * <p>
107      * An internal sequence number is used to differentiate RecoveryCoordinator
108      * objects used for the same Coordinator object within a process. This is
109      * so that they each get a unique object identifier.
110      *
111      * @param globalTID The global transaction identifier.
112      * @param sequence An internal sequence number to differentiate objects.
113      *
114      * @return
115      *
116      * @see
117      */

118     RecoveryCoordinatorImpl(GlobalTID globalTID, int sequence) {
119
120         this.globalTID = globalTID;
121         internalSeq = sequence;
122
123         // MODIFICATION (Ram Jeyaraman) comment out the code
124
// below, as it does nothing.
125
/*
126         byte[] tidBytes = globalTID.toBytes();
127         byte[] id = new byte[tidBytes.length + 4];
128         System.arraycopy(tidBytes, 0, id, 4, tidBytes.length);
129         id[0] = (byte) internalSeq;
130         id[1] = (byte)(internalSeq >> 8);
131         id[2] = (byte)(internalSeq >> 16);
132         id[3] = (byte)(internalSeq >> 24);
133         */

134     }
135
136     /**
137      * Cleans up the state of the object.
138      *
139      * @param
140      *
141      * @return
142      *
143      * @see
144      */

145     public void finalize() {
146
147         globalTID = null;
148         internalSeq = 0;
149     }
150
151     /**
152      * Informs the Transaction Service that the given Resource object has been
153      * prepared but has not received a commit or rollback operation.
154      * <p>
155      * If the transaction outcome is unknown, the Resource object passed
156      * on this operation will be called at some later time for
157      * commit or rollback.
158      *
159      * @param res The Resource to be recovered.
160      *
161      * @return The state of the transaction.
162      *
163      * @exception NotPrepared The transaction for which the
164      * RecoveryCoordinator was created has not prepared.
165      *
166      * @see
167      */

168     public Status replay_completion(Resource res) throws NotPrepared {
169     
170         if(_logger.isLoggable(Level.FINE))
171         {
172              _logger.logp(Level.FINE,"RecoveryCoordinatorImpl",
173                     "replay_completion()","replay_completion on Resource:"+
174                     res);
175         }
176
177
178         Status result = Status.StatusRolledBack;
179
180         CoordinatorImpl coord = RecoveryManager.getCoordinator(globalTID);
181         if (coord != null) {
182             try {
183                 result = coord.get_status();
184             } catch (SystemException exc) {}
185         }
186
187         switch (result.value()) {
188
189         /*
190          * If the transaction is still active, raise the NotPrepared
191          * exception. The Coordinator must be marked rollback-only at
192          * this point because we cannot allow the transaction to
193          * complete if a participant has failed.
194          */

195
196         case Status._StatusActive :
197         case Status._StatusMarkedRollback :
198             try {
199                 coord.rollback_only();
200             } catch (Throwable JavaDoc exc) {}
201
202             throw new NotPrepared();
203
204         /*
205          * If the transaction is prepared, the caller must wait for the
206          * Coordinator to tell it what to do, so return an unknown status, and
207          * do nothing. Note that if this Coordinator is sitting waiting for
208          * its superior, this could take a int time.
209          */

210
211         case Status._StatusPrepared :
212             result = Status.StatusUnknown;
213             break;
214
215         /*
216          * If the transaction has been committed, the caller will receive
217          * a commit.
218          *
219          * GDH If the transaction is commiting then we pass this on
220          * to the caller. This state (added in OTS 1.1 means that
221          * TopCoordinator.recover must now accept the COMMITTING state.
222          */

223
224         case Status._StatusCommitting :
225             // MODIFICATION (Ram Jeyaraman) commented out the code below,
226
// since a StatusCommitting will be upgraded to Committed in
227
// the subordinate.
228
/*
229             // (Ram Jeyaraman) let the subordinate wait, and allow the root
230             // finish driving the commit.
231             result = Status.StatusUnknown;
232             */

233             break;
234
235         case Status._StatusCommitted :
236             break;
237
238         case Status._StatusRolledBack :
239
240             // If the transaction has been rolled back, and there is
241
// no Coordinator for the transaction, we must invoke rollback
242
// directly, as it will not be done otherwise. However for
243
// proxies, this rollback cannot be done from this thread as
244
// it would cause deadlock in the server requesting resync.
245

246             if (coord == null) {
247
248                 if (!Configuration.getProxyChecker().isProxy(res)) {
249                     rollbackOrphan(res);
250                 } else {
251
252                     // We must pass a duplicate of the proxy to the
253
// rollback thread because this proxy will be destroyed
254
// when the replay_completion request returns
255
// to the remote server.
256

257                     try {
258                         OrphanRollbackThread rollbackThread =
259                             new OrphanRollbackThread(
260                                 this, (Resource) res._duplicate());
261                         rollbackThread.start();
262                     } catch (SystemException exc) {}
263                 }
264             }
265
266             break;
267
268         /*
269          * In any other situation, assume that the transaction has been rolled
270          * back. As there is a Coordinator, it will direct the Resource to roll
271          * back.
272          */

273
274         default :
275             result = Status.StatusRolledBack;
276         }
277
278         return result;
279     }
280
281     // same as replay_completion(res) : added for delegated recovery support
282
public Status replay_completion(Resource res, String JavaDoc logPath) throws NotPrepared {
283     
284         if(_logger.isLoggable(Level.FINE))
285         {
286          _logger.logp(Level.FINE,"RecoveryCoordinatorImpl",
287             "replay_completion()","replay_completion on Resource:"+ res);
288         }
289
290         Status result = Status.StatusRolledBack;
291
292         CoordinatorImpl coord = DelegatedRecoveryManager.getCoordinator(globalTID, logPath);
293         if (coord != null) {
294             try {
295                 result = coord.get_status();
296             } catch (SystemException exc) {}
297         }
298
299         switch (result.value()) {
300
301         /*
302          * If the transaction is still active, raise the NotPrepared
303          * exception. The Coordinator must be marked rollback-only at
304          * this point because we cannot allow the transaction to
305          * complete if a participant has failed.
306          */

307
308         case Status._StatusActive :
309         case Status._StatusMarkedRollback :
310             try {
311                 coord.rollback_only();
312             } catch (Throwable JavaDoc exc) {}
313
314             throw new NotPrepared();
315
316         /*
317          * If the transaction is prepared, the caller must wait for the
318          * Coordinator to tell it what to do, so return an unknown status, and
319          * do nothing. Note that if this Coordinator is sitting waiting for
320          * its superior, this could take a int time.
321          */

322
323         case Status._StatusPrepared :
324             result = Status.StatusUnknown;
325             break;
326
327         /*
328          * If the transaction has been committed, the caller will receive
329          * a commit.
330          *
331          * GDH If the transaction is commiting then we pass this on
332          * to the caller. This state (added in OTS 1.1 means that
333          * TopCoordinator.recover must now accept the COMMITTING state.
334          */

335
336         case Status._StatusCommitting :
337             // MODIFICATION (Ram Jeyaraman) commented out the code below,
338
// since a StatusCommitting will be upgraded to Committed in
339
// the subordinate.
340
/*
341             // (Ram Jeyaraman) let the subordinate wait, and allow the root
342             // finish driving the commit.
343             result = Status.StatusUnknown;
344             */

345             break;
346
347         case Status._StatusCommitted :
348             break;
349
350         case Status._StatusRolledBack :
351
352             // If the transaction has been rolled back, and there is
353
// no Coordinator for the transaction, we must invoke rollback
354
// directly, as it will not be done otherwise. However for
355
// proxies, this rollback cannot be done from this thread as
356
// it would cause deadlock in the server requesting resync.
357

358             if (coord == null) {
359
360                 if (!Configuration.getProxyChecker().isProxy(res)) {
361                     rollbackOrphan(res);
362                 } else {
363
364                     // We must pass a duplicate of the proxy to the
365
// rollback thread because this proxy will be destroyed
366
// when the replay_completion request returns
367
// to the remote server.
368

369                     try {
370                         OrphanRollbackThread rollbackThread =
371                             new OrphanRollbackThread(
372                                 this, (Resource) res._duplicate());
373                         rollbackThread.start();
374                     } catch (SystemException exc) {}
375                 }
376             }
377
378             break;
379
380         /*
381          * In any other situation, assume that the transaction has been rolled
382          * back. As there is a Coordinator, it will direct the Resource to roll
383          * back.
384          */

385
386         default :
387             result = Status.StatusRolledBack;
388         }
389
390         return result;
391     }
392
393     /**
394      * This method invoked rollback on the Resource that is passed as a
395      * parameter.
396      * <p>
397      * This procedure may be called as the main procedure of a new thread,
398      * which must be done for remote Resource objects
399      * during resync to avoid the possibility of deadlock during resync.
400      *
401      * <p>
402      * It is called directly when the Resource is not a proxy.
403      *
404      * @param res The Resource to be rolled back.
405      *
406      * @return
407      *
408      * @see
409      */

410     void rollbackOrphan(Resource res) {
411
412         try {
413             res.rollback();
414         } catch(Throwable JavaDoc exc) {
415
416             // If the rollback raised a heuristic exception, it can
417
// only be reported in a message as it will never reach
418
// the Coordinator.
419

420             if (exc instanceof HeuristicCommit ||
421                     exc instanceof HeuristicMixed ||
422                     exc instanceof HeuristicHazard) {
423                 _logger.log(Level.WARNING,"jts.heuristic_exception",exc.toString());
424             } else {}
425         }
426
427         // We must release the proxy now.
428

429         res._release();
430     }
431
432     /**
433      * Creates the RecoveryCoordinatorImpl with the given key.
434      * <p>
435      * This is done when the RecoveryCoordinator object is recreated after the
436      * server has been restarted.
437      * <p>
438      * The first four bytes of the key are an internal sequence number used to
439      * differentiate RecoveryCoordinator objects created in the
440      * same process for the same transaction.
441      * <p>
442      * The rest of the key is the global transaction identifier.
443      *
444      * @param key The key for the object.
445      *
446      * @return
447      *
448      * @see
449      */

450     RecoveryCoordinatorImpl(byte[] key) {
451
452         // Get the global transaction identifier from the key.
453

454         byte[] tidBytes = new byte[key.length - 4];
455
456         // BUGFIX (Ram Jeyaraman) changed the order of array copy.
457
// previously, an source and destination array was wrong.
458
//System.arraycopy(tidBytes, 0, key, 4, tidBytes.length);
459
System.arraycopy(key, 4, tidBytes, 0, tidBytes.length);
460         
461         globalTID = new GlobalTID(tidBytes);
462
463         // Ensure that recovery has completed so that
464
// we can get the Coordinator.
465

466         RecoveryManager.waitForRecovery();
467
468         // Leave other members at the default values.
469
}
470
471     /**
472      * Returns the CORBA Object which represents this object.
473      *
474      * @param
475      *
476      * @return The CORBA object.
477      *
478      * @see
479      */

480     synchronized final RecoveryCoordinator object() {
481
482         if (thisRef == null) {
483             if (poa == null) {
484                 poa = Configuration.getPOA("RecoveryCoordinator"/*#Frozen*/);
485                 recoverable = Configuration.isRecoverable();
486             }
487
488             try {
489
490                 if (recoverable && globalTID != null) {
491                     // Create the object id from the global transaction
492
// identifier and the internal sequence number.
493

494                     byte[] tidBytes = globalTID.toBytes();
495                     byte[] id = new byte[tidBytes.length + 4];
496                     System.arraycopy(tidBytes, 0, id, 4, tidBytes.length);
497                     id[0] = (byte) internalSeq;
498                     id[1] = (byte)(internalSeq >> 8);
499                     id[2] = (byte)(internalSeq >> 16);
500                     id[3] = (byte)(internalSeq >> 24);
501
502                     // Activate the object and create the reference.
503

504                     poa.activate_object_with_id(id, this);
505
506                     org.omg.CORBA.Object JavaDoc obj =
507                         poa.create_reference_with_id(
508                             id, RecoveryCoordinatorHelper.id());
509                     thisRef = RecoveryCoordinatorHelper.narrow(obj);
510                     //thisRef = (RecoveryCoordinator) this;
511
} else {
512                     poa.activate_object(this);
513                     org.omg.CORBA.Object JavaDoc obj = poa.servant_to_reference(this);
514                     thisRef = RecoveryCoordinatorHelper.narrow(obj);
515                     //thisRef = (RecoveryCoordinator)this;
516
}
517             } catch(Exception JavaDoc exc) {
518                 _logger.log(Level.SEVERE,"jts.create_recoverycoordinator_error");
519                  String JavaDoc msg = LogFormatter.getLocalizedMessage(_logger,
520                                         "jts.create_recoverycoordinator_error");
521                   throw new org.omg.CORBA.INTERNAL JavaDoc(msg);
522             }
523         }
524
525         return thisRef;
526     }
527
528     /**
529      * Destroys the RecoveryCoordinatorImpl object.
530      *
531      * @param
532      *
533      * @return
534      *
535      * @see
536      */

537     synchronized final void destroy() {
538
539         try {
540             if (poa != null && thisRef != null) {
541                 poa.deactivate_object(poa.reference_to_id(thisRef));
542                 thisRef = null;
543             } else {
544                 // BUGFIX(Ram J) It is possible that the
545
// RecoveryCoordinator object was activated via the activation
546
// daemon. In that case, there is no guarantee
547
// that poa and thisRef are set to a meaningful value.
548
// So, try to deactivate the RecoveryCoordinator object anyway.
549

550                 POA rcPoa = null;
551                 if (poa == null) {
552                     rcPoa = Configuration.getPOA("RecoveryCoordinator"/*#Frozen*/);
553                 } else {
554                     rcPoa = poa;
555                 }
556
557                 if (thisRef == null) {
558                     rcPoa.deactivate_object(rcPoa.servant_to_id(this));
559                 } else {
560                     rcPoa.deactivate_object(rcPoa.reference_to_id(thisRef));
561                     thisRef = null;
562                 }
563             }
564         } catch( Exception JavaDoc exc ) {
565                 _logger.log(Level.WARNING,"jts.object_destroy_error","RecoveryCoordinator");
566         }
567
568         finalize();
569     }
570 }
571
572 /**
573  * This class is provided to allow a Resource to be rolled back by the
574  * RecoveryCoordinator on a new thread. This is required for
575  * Resource objects which are proxies because deadlock would occur
576  * if the rollback was called from the same thread as the one on
577  * which the replay_completion was executing.
578  *
579  * @version 0.01
580  *
581  * @author Simon Holdsworth, IBM Corporation
582  *
583  * @see
584  */

585 class OrphanRollbackThread extends Thread JavaDoc {
586     Resource resource = null;
587     RecoveryCoordinatorImpl recovery = null;
588
589     /**
590      * OrphanRollbackThread constructor.
591      *
592      * @param recovery
593      * @param resource
594      *
595      * @return
596      *
597      * @see
598      */

599     OrphanRollbackThread(RecoveryCoordinatorImpl recovery,
600             Resource resource) {
601         this.resource = resource;
602         this.recovery = recovery;
603         setName("JTS Orphan Rollback Thread"/*#Frozen*/);
604     }
605
606     /**
607      * Calls the RecoveryCoordinator to rollback the Resource.
608      *
609      * @param
610      *
611      * @return
612      *
613      * @see
614      */

615     public void run() {
616         recovery.rollbackOrphan(resource);
617     }
618 }
619
Popular Tags