1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.objectweb.jotm;
17
18 import java.nio.ByteBuffer;
19 import java.rmi.RemoteException;
20 import java.util.List;
21 import java.util.Vector;
22
23 import javax.rmi.PortableRemoteObject;
24 import javax.transaction.InvalidTransactionException;
25 import javax.transaction.RollbackException;
26 import javax.transaction.Status;
27 import javax.transaction.Synchronization;
28 import javax.transaction.SystemException;
29 import javax.transaction.Transaction;
30 import javax.transaction.TransactionManager;
31 import javax.transaction.TransactionRolledbackException;
32 import javax.transaction.xa.XAException;
33 import javax.transaction.xa.XAResource;
34
35 import org.objectweb.howl.log.xa.XACommittingTx;
36
37
38
39
40 class SLog {
41
42 private Vector loggedResources = new Vector();
43 private Vector loggedByteResources = new Vector();
44
45 private Vector loggedXids = new Vector();
46
47 private Vector loggedJavaxXids = new Vector();
48
49 int decision;
50 static final int DECISION_TO_COMMIT = 1;
51 static final int DECISION_TO_ROLLBACK = 2;
52
53 public void addResource(XAResource res, Xid xid, javax.transaction.xa.Xid javaxxid) {
54 if (TraceTm.jta.isDebugEnabled()) {
55 TraceTm.jta.debug("res= " + res);
56 TraceTm.jta.debug("xid= " + xid);
57 TraceTm.jta.debug("javaxxid= " + javaxxid);
58 }
59 loggedResources.addElement(res);
60 loggedByteResources.addElement(res.toString().getBytes());
61 loggedXids.addElement(xid);
62 loggedJavaxXids.addElement(javaxxid);
63 }
64
65
66
67
68 public List getLoggedResources() {
69 if (TraceTm.jta.isDebugEnabled()) {
70 TraceTm.jta.debug("logged resources=" + loggedResources);
71 }
72 return loggedResources;
73 }
74
75 public List getByteLoggedResources() {
76 if (TraceTm.jta.isDebugEnabled()) {
77 TraceTm.jta.debug("logged resources=" + loggedResources);
78 }
79 return loggedByteResources;
80 }
81
82 public List getLoggedXids() {
83 return loggedXids;
84 }
85
86 public List getLoggedJavaxXids() {
87 return loggedJavaxXids;
88 }
89
90 public void flushLog(int decide) {
91 if (TraceTm.jta.isDebugEnabled()) {
92 TraceTm.jta.debug("decide=" + decide);
93 }
94 decision = decide;
95
96
97 }
98
99 public void forgetLog() {
100 if (TraceTm.jta.isDebugEnabled()) {
101 TraceTm.jta.debug("forget log");
102 }
103
104 }
105 }
106
107 class JotmTransactionRolledbackException extends TransactionRolledbackException {
108 private static final long serialVersionUID = 1L;
109
110 public JotmTransactionRolledbackException() {
111 super();
112 }
113
114 public JotmTransactionRolledbackException(String message) {
115 super(message);
116 }
117
118 public JotmTransactionRolledbackException(String message, Throwable cause) {
119 super(message);
120 detail = cause;
121 }
122
123 public JotmTransactionRolledbackException(Throwable cause) {
124 super();
125 detail = cause;
126 }
127 }
128
129
130
131
132
133 public class SubCoordinator extends PortableRemoteObject implements Resource {
134
135
136
137
138
139
140
141
142 private TransactionImpl tx = null;
143
144
145
146
147
148
149 private Vector synchroList = new Vector();
150
151
152
153
154
155
156 private Vector resourceList = new Vector();
157 private Vector javaxxidList = new Vector();
158
159
160
161
162
163
164 private TransactionManager tm;
165
166
167
168
169 private Xid xid = null;
170
171
172
173
174 private SLog log = null;
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203 private int status = Status.STATUS_ACTIVE;
204
205 private Exception rollbackCause;
206
207
208
209 private boolean beforeCompletionDone = false;
210
211 static final String JOTM_RD_ONLY = "JOTM_RD_ONLY";
212
213 static final byte[] RT1 = "RR1".getBytes();
214 static final byte[] RT2 = "RR2".getBytes();
215 static final byte[] JOTMDONE = "RR3JOTMDONE".getBytes();
216
217
218
219
220
221
222
223
224 SubCoordinator(TransactionImpl tx, Xid xid) throws RemoteException {
225
226 if (TraceTm.jta.isDebugEnabled()) {
227 TraceTm.jta.debug("tx=" + tx + ", xid=" + xid);
228 }
229
230 this.tx = tx;
231 this.xid = xid;
232 this.tm = Current.getTransactionManager();
233
234 beforeCompletionDone = false;
235 }
236
237
238
239
240
241
242
243
244
245
246 @Override
247 public int prepare() throws RemoteException {
248
249 if (TraceTm.jta.isDebugEnabled()) {
250 TraceTm.jta.debug("status=" + StatusHelper.getStatusName(status));
251 }
252
253 try {
254 tx.doDetach(XAResource.TMSUCCESS);
255 } catch (SystemException e) {
256
257 if (TraceTm.jta.isDebugEnabled()) {
258 String error = "Error when detaching XAResource:" + e + "--" + e.getMessage();
259 TraceTm.jta.debug(error);
260 }
261 }
262
263 switch (status) {
264 case Status.STATUS_MARKED_ROLLBACK:
265
266
267
268
269 status = Status.STATUS_ROLLING_BACK;
270 return Resource.VOTE_ROLLBACK;
271 case Status.STATUS_COMMITTED:
272 return Resource.VOTE_COMMIT;
273 default:
274 doBeforeCompletion(true);
275 break;
276 }
277
278
279
280 if (status == Status.STATUS_MARKED_ROLLBACK) {
281 TraceTm.jotm.info("Rollback during beforeCompletion in SubCoordinator.prepare");
282
283 status = Status.STATUS_ROLLING_BACK;
284 return Resource.VOTE_ROLLBACK;
285 }
286
287 int ret = doPrepare();
288
289 if (ret == Resource.VOTE_READONLY) {
290
291 doAfterCompletion();
292 }
293
294 if (TraceTm.jta.isDebugEnabled()) {
295 TraceTm.jta.debug("vote = " + ret);
296 }
297
298 return ret;
299 }
300
301
302
303
304
305 @Override
306 public void rollback() throws RemoteException {
307
308 if (TraceTm.jta.isDebugEnabled()) {
309 TraceTm.jta.debug("status=" + StatusHelper.getStatusName(status));
310 }
311
312 try {
313 tx.doDetach(XAResource.TMSUCCESS);
314 } catch (SystemException e) {
315 if (TraceTm.jta.isDebugEnabled()) {
316 String error = "Error when detaching XAResource:" + e + "--" + e.getMessage();
317 TraceTm.jta.debug(error);
318 }
319 }
320
321 switch (status) {
322 case Status.STATUS_ACTIVE:
323 case Status.STATUS_MARKED_ROLLBACK:
324 case Status.STATUS_ROLLING_BACK:
325 if (TraceTm.jotm.isDebugEnabled()) {
326 TraceTm.jotm.debug("transaction rolling back");
327 }
328 break;
329 case Status.STATUS_PREPARED:
330 if (TraceTm.jotm.isDebugEnabled()) {
331 TraceTm.jotm.debug("should not rollback a prepared transaction");
332 }
333 break;
334 case Status.STATUS_ROLLEDBACK:
335 if (TraceTm.jotm.isDebugEnabled()) {
336 TraceTm.jotm.debug("already rolledback");
337 }
338 return;
339 default:
340 TraceTm.jotm.error("rollback: bad status: " + StatusHelper.getStatusName(status));
341 return;
342 }
343 doBeforeCompletion(false);
344 doRollback();
345 }
346
347
348
349
350 @Override
351 public void commit() throws RemoteException {
352
353 if (TraceTm.jta.isDebugEnabled()) {
354 TraceTm.jta.debug("status=" + StatusHelper.getStatusName(status));
355 }
356
357 switch (status) {
358 case Status.STATUS_PREPARED:
359 break;
360 default:
361 TraceTm.jotm.error("commit: bad status: " + StatusHelper.getStatusName(status));
362 return;
363 }
364 doCommit();
365 }
366
367
368
369
370
371 @Override
372 public void commit_one_phase() throws RemoteException {
373
374 if (TraceTm.jta.isDebugEnabled()) {
375 TraceTm.jta.debug("status=" + StatusHelper.getStatusName(status));
376 }
377
378 switch (status) {
379 case Status.STATUS_ROLLEDBACK:
380 try {
381 tx.doDetach(XAResource.TMSUCCESS);
382 } catch (SystemException e) {
383
384 if (TraceTm.jta.isDebugEnabled()) {
385 String error = "Error when detaching XAResource:" + e + "--" + e.getMessage();
386 TraceTm.jta.debug(error);
387 }
388 }
389
390 throw new JotmTransactionRolledbackException(rollbackCause);
391
392 case Status.STATUS_MARKED_ROLLBACK:
393 doBeforeCompletion(false);
394 try {
395 tx.doDetach(XAResource.TMSUCCESS);
396 } catch (SystemException e) {
397
398 if (TraceTm.jta.isDebugEnabled()) {
399 String error = "Error when detaching XAResource:" + e + "--" + e.getMessage();
400 TraceTm.jta.debug(error);
401 }
402 }
403 doRollback();
404
405 throw new JotmTransactionRolledbackException(rollbackCause);
406
407 case Status.STATUS_COMMITTED:
408 try {
409 tx.doDetach(XAResource.TMSUCCESS);
410 } catch (SystemException e) {
411
412 if (TraceTm.jta.isDebugEnabled()) {
413 String error = "Error when detaching XAResource:" + e + "--" + e.getMessage();
414 TraceTm.jta.debug(error);
415 }
416 }
417 return;
418 default:
419 doBeforeCompletion(true);
420 try {
421 tx.doDetach(XAResource.TMSUCCESS);
422 } catch (SystemException e) {
423
424 if (TraceTm.jta.isDebugEnabled()) {
425 String error = "Error when detaching XAResource:" + e + "--" + e.getMessage();
426 TraceTm.jta.debug(error);
427 }
428 }
429 break;
430 }
431
432
433
434 if (TraceTm.jta.isDebugEnabled()) {
435 TraceTm.jta.debug("status=" + StatusHelper.getStatusName(status));
436 }
437
438
439
440 if (status == Status.STATUS_MARKED_ROLLBACK) {
441 TraceTm.jotm.info("Rollback during beforeCompletion in SubCoordinator.commit_one_phase");
442 doRollback();
443
444 throw new JotmTransactionRolledbackException(rollbackCause);
445
446 }
447
448
449
450 if (resourceList.size() == 1) {
451 doOnePhaseCommit();
452 return;
453 }
454
455
456
457 int vote = doPrepare();
458
459 switch (vote) {
460 case Resource.VOTE_COMMIT:
461 doCommit();
462 break;
463 case Resource.VOTE_READONLY:
464 doAfterCompletion();
465 break;
466 case Resource.VOTE_ROLLBACK:
467 doRollback();
468
469 throw new JotmTransactionRolledbackException(rollbackCause);
470
471 }
472 }
473
474
475
476
477 @Override
478 public void forget() throws RemoteException {
479 if (TraceTm.jta.isDebugEnabled()) {
480 TraceTm.jta.debug("SubCoordinator.forget()");
481 }
482 doForget();
483 }
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503 public void addSynchronization(Synchronization synchro) throws RollbackException, IllegalStateException {
504
505 if (TraceTm.jta.isDebugEnabled()) {
506 TraceTm.jta.debug("synchro=" + synchro);
507 TraceTm.jta.debug("status=" + StatusHelper.getStatusName(status));
508 }
509
510
511 boolean markedRollback = false;
512
513 switch (status) {
514 case Status.STATUS_MARKED_ROLLBACK:
515 case Status.STATUS_ROLLEDBACK:
516 markedRollback = true;
517 break;
518 case Status.STATUS_ACTIVE:
519 break;
520 default:
521 String errorMsg = "addSynchronization: bad status = " + StatusHelper.getStatusName(status);
522 TraceTm.jotm.error(errorMsg);
523 throw new IllegalStateException(errorMsg);
524 }
525
526
527 synchroList.addElement(synchro);
528
529
530
531
532
533
534 if (markedRollback) {
535 if (TraceTm.jta.isDebugEnabled()) {
536 TraceTm.jta.debug("SubCoordinator.addSynchronization: transaction rollback only");
537 }
538 throw new RollbackException();
539 }
540 }
541
542
543
544
545
546
547
548
549
550
551
552
553
554 public synchronized boolean addResource(XAResource xares) throws IllegalStateException {
555
556 if (TraceTm.jta.isDebugEnabled()) {
557 TraceTm.jta.debug("xares=" + xares);
558 TraceTm.jta.debug("status=" + StatusHelper.getStatusName(status));
559 }
560
561
562 boolean markedRollback = false;
563
564 switch (status) {
565 case Status.STATUS_MARKED_ROLLBACK:
566 markedRollback = true;
567 break;
568 case Status.STATUS_ACTIVE:
569 break;
570 default:
571 String errorMsg = "SubCoordinator.addResource: bad status= " + StatusHelper.getStatusName(status);
572 TraceTm.jotm.error(errorMsg);
573 throw new IllegalStateException(errorMsg);
574 }
575
576
577
578
579 boolean found = false;
580
581 for (int i = 0; i < resourceList.size(); i++) {
582 XAResource res = (XAResource) resourceList.elementAt(i);
583
584 try {
585 if (res.isSameRM(xares)) {
586 found = true;
587 break;
588 }
589 } catch (XAException e) {
590 String error = "Cannot send res.isSameRM:" + e + " (error code = " + e.errorCode + ") --"
591 + e.getMessage();
592 TraceTm.jotm.error("Exception on resource.isSameRM: " + error);
593 }
594 }
595
596
597
598 if (found == false) {
599 if (TraceTm.jta.isDebugEnabled()) {
600 TraceTm.jta.debug("new XAResource added to the list");
601 }
602 resourceList.addElement(xares);
603 }
604
605
606
607
608
609
610 if (markedRollback) {
611 TraceTm.jta.debug("SubCoordinator.addResource: transaction set rollback only");
612 }
613
614 return found;
615 }
616
617
618
619
620
621
622 public synchronized void addJavaxXid(javax.transaction.xa.Xid javaxxid) {
623 if (TraceTm.jta.isDebugEnabled()) {
624 TraceTm.jta.debug("addJavaxXid javaxxid=" + javaxxid);
625 }
626
627
628 javaxxidList.addElement(javaxxid);
629 if (TraceTm.jta.isDebugEnabled()) {
630 TraceTm.jta.debug("new JavaxXid added to the list");
631 }
632 }
633
634
635
636
637
638
639
640 public javax.transaction.xa.Xid getJavaxXid(int xaresindex) {
641 javax.transaction.xa.Xid myjavaxxid = (javax.transaction.xa.Xid) javaxxidList.elementAt(xaresindex);
642 return myjavaxxid;
643 }
644
645
646
647
648 public int getStatus() {
649 if (TraceTm.jta.isDebugEnabled()) {
650 TraceTm.jta.debug("status=" + StatusHelper.getStatusName(status));
651 }
652 return status;
653 }
654
655
656
657
658 public void setRollbackOnly() {
659
660 if (TraceTm.jta.isDebugEnabled()) {
661 TraceTm.jta.debug("status=" + StatusHelper.getStatusName(status));
662 }
663
664 switch (status) {
665 case Status.STATUS_ACTIVE:
666 case Status.STATUS_UNKNOWN:
667 case Status.STATUS_PREPARING:
668 status = Status.STATUS_MARKED_ROLLBACK;
669 break;
670 case Status.STATUS_MARKED_ROLLBACK:
671 case Status.STATUS_ROLLING_BACK:
672 break;
673 case Status.STATUS_PREPARED:
674 case Status.STATUS_COMMITTED:
675 case Status.STATUS_ROLLEDBACK:
676 case Status.STATUS_NO_TRANSACTION:
677 case Status.STATUS_COMMITTING:
678 TraceTm.jotm.error("Cannot set transaction as rollback only");
679 TraceTm.jotm.error("Bad status=" + StatusHelper.getStatusName(status));
680 break;
681 }
682 }
683
684
685
686
687
688
689
690
691 private void doForget() throws RemoteException {
692 if (TraceTm.jta.isDebugEnabled()) {
693 TraceTm.jta.debug("SubCoordinator.doForget()");
694 }
695
696 boolean exception = false;
697
698 for (int i = 0; i < resourceList.size(); i++) {
699
700
701 XAResource xar = (XAResource) resourceList.elementAt(i);
702
703 javax.transaction.xa.Xid myjavaxxid = (javax.transaction.xa.Xid) javaxxidList.elementAt(i);
704
705 if (TraceTm.jta.isDebugEnabled()) {
706 TraceTm.jta.debug("myjavaxxid= " + myjavaxxid);
707 TraceTm.jta.debug("forgotten with resource= " + xar);
708 }
709
710 try {
711 xar.forget(myjavaxxid);
712 } catch (XAException e) {
713 String error = "Cannot send xar.forget:" + e + " (error code = " + e.errorCode + ") --"
714 + e.getMessage();
715 TraceTm.jotm.error("Got XAException from xar.forget: " + error);
716 exception = true;
717 }
718 }
719
720 if (exception) {
721 throw new RemoteException("XAException on forget");
722 }
723
724 unexportObject(this);
725 }
726
727
728
729
730 private synchronized int doPrepare() throws RemoteException {
731 if (TraceTm.jta.isDebugEnabled()) {
732 TraceTm.jta.debug("SubCoordinator.doPrepare()");
733 }
734
735 int ret = VOTE_READONLY;
736 int errors = 0;
737
738
739
740 if (resourceList.size() == 0) {
741
742 Current.getCurrent().incrementCommitCounter();
743 status = Status.STATUS_COMMITTED;
744 return ret;
745 }
746
747
748
749
750
751 log = new SLog();
752
753
754
755
756 status = Status.STATUS_PREPARING;
757
758 for (int i = 0; i < resourceList.size(); i++) {
759 XAResource res = (XAResource) resourceList.elementAt(i);
760 javax.transaction.xa.Xid myjavaxxid = (javax.transaction.xa.Xid) javaxxidList.elementAt(i);
761
762 Xid xid = new XidImpl(this.xid, i);
763
764 if (errors > 0) {
765
766 if (TraceTm.jta.isDebugEnabled()) {
767 TraceTm.jta.debug("xid= " + xid);
768 TraceTm.jta.debug("myjavaxxid= " + myjavaxxid);
769 TraceTm.jta.debug("rolled back with resource= " + res);
770 }
771
772 try {
773 res.rollback(myjavaxxid);
774
775 } catch (XAException e) {
776 String error = "Cannot send res.rollback:" + e + " (error code = " + e.errorCode + ") --"
777 + e.getMessage();
778 TraceTm.jotm.error("Got XAException from res.rollback: " + error);
779
780 }
781 } else {
782 if (TraceTm.jta.isDebugEnabled()) {
783 TraceTm.jta.debug("xid= " + xid);
784 TraceTm.jta.debug("myjavaxxid= " + myjavaxxid);
785 TraceTm.jta.debug("prepared with resource= " + res);
786 }
787
788 try {
789 switch (res.prepare(myjavaxxid)) {
790
791 case XAResource.XA_OK:
792 log.addResource(res, xid, myjavaxxid);
793 ret = VOTE_COMMIT;
794 if (TraceTm.jta.isDebugEnabled()) {
795 TraceTm.jta.debug("Prepare= XA_OK");
796 }
797 break;
798 case XAResource.XA_RDONLY:
799 if (TraceTm.jta.isDebugEnabled()) {
800 TraceTm.jta.debug("Prepare= XA_RDONLY");
801 }
802 break;
803 }
804 } catch (XAException e) {
805 String error = "Cannot send res.prepare:" + e + " (error code = " + e.errorCode + ") --"
806 + e.getMessage();
807 TraceTm.jotm.error("Got XAException from res.prepare: " + error);
808 ret = VOTE_ROLLBACK;
809 errors++;
810 }
811 }
812 }
813
814
815
816
817 switch (ret) {
818 case VOTE_READONLY:
819
820 Current.getCurrent().incrementCommitCounter();
821 status = Status.STATUS_COMMITTED;
822 if (TraceTm.jta.isDebugEnabled()) {
823 TraceTm.jta.debug("VOTE_READONLY");
824 }
825 break;
826 case VOTE_COMMIT:
827 status = Status.STATUS_PREPARED;
828 if (TraceTm.jta.isDebugEnabled()) {
829 TraceTm.jta.debug("VOTE_COMMIT");
830 }
831 break;
832 case VOTE_ROLLBACK:
833 status = Status.STATUS_ROLLING_BACK;
834 if (TraceTm.jta.isDebugEnabled()) {
835 TraceTm.jta.debug("VOTE_ROLLBACK");
836 }
837 break;
838 }
839
840
841 return ret;
842 }
843
844
845
846
847 private synchronized int doCommit() throws RemoteException {
848 if (TraceTm.jta.isDebugEnabled()) {
849 TraceTm.jta.debug("SubCoordinator.doCommit()");
850 }
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891 if (log == null) {
892 TraceTm.jotm.error("doCommit: no log");
893 return -1;
894 }
895
896 boolean successfulcommit = true;
897 int commitnb = 0;
898 int heuristicnb = 0;
899
900 List loggedResources = log.getLoggedResources();
901 List byteloggedResources = log.getByteLoggedResources();
902 List loggedXids = log.getLoggedXids();
903 List loggedJavaxXids = log.getLoggedJavaxXids();
904
905 XACommittingTx xaCommitTx = null;
906 XACommittingTx xaCommitTxRewrite = null;
907
908 byte[][] recoveryBuffer = new byte[loggedResources.size() + 1][];
909
910 byte[] recoveryRecord1 = null;
911 byte[] recoveryRecord2 = null;
912 ByteBuffer rr1 = null;
913 ByteBuffer rr2 = null;
914
915 byte[][] jotmDoneRecord = new byte[1][11];
916
917 if (Current.getDefaultRecovery()) {
918 Xid txxid = tx.getXid();
919
920 int txxidfi = txxid.getFormatId();
921 byte[] txxidgti = txxid.getGlobalTransactionId();
922 byte[] txxidbq = txxid.getBranchQualifier();
923 int txxidlength = 4 + txxidgti.length + txxidbq.length;
924
925
926 int gridlen = txxidgti.length;
927 int bqlen = txxidbq.length;
928
929 String txdate = tx.getTxDate().toString();
930 int txdatelength = txdate.length();
931 long rcdate = System.currentTimeMillis();
932
933 recoveryRecord1 = new byte[3 + 8 + 4 + 4 + gridlen + 4 + bqlen + 4 + txdatelength + 4];
934
935 rr1 = ByteBuffer.wrap(recoveryRecord1);
936 rr1.put(RT1);
937 rr1.putLong(rcdate);
938 rr1.putInt(txxidfi);
939 rr1.putInt(txxidgti.length);
940 rr1.put(txxidgti);
941 rr1.putInt(txxidbq.length);
942 rr1.put(txxidbq);
943 rr1.putInt(txdatelength);
944 rr1.put(txdate.getBytes());
945 rr1.putInt(loggedResources.size());
946
947 recoveryBuffer[0] = rr1.array();
948
949 for (int i = 0; i < loggedResources.size(); i++) {
950 XAResource res = (XAResource) loggedResources.get(i);
951 byte[] resname = (byte[]) byteloggedResources.get(i);
952
953 Xid xid = (Xid) loggedXids.get(i);
954 int rmindex = 99;
955
956 if (TraceTm.recovery.isDebugEnabled()) {
957 TraceTm.recovery.debug("recovery xid= " + xid);
958 TraceTm.recovery.debug("recovery resource= " + res);
959 }
960
961 int resnamelength = resname.length;
962 String resclassname = res.getClass().getName();
963 int resclassnamelength = resclassname.length();
964
965 int xidfi = xid.getFormatId();
966 byte[] xidgti = xid.getGlobalTransactionId();
967 byte[] xidbq = xid.getBranchQualifier();
968 int rr2gtilen = xidgti.length;
969 int rr2bqlen = xidbq.length;
970
971
972
973 recoveryRecord2 = new byte[3 + 4 + 4 + resnamelength + 4 + resclassnamelength + 4 + 4 + rr2gtilen + 4
974 + rr2bqlen + 4];
975
976 rr2 = ByteBuffer.wrap(recoveryRecord2);
977 rr2.put(RT2);
978 rr2.putInt(rmindex);
979 rr2.putInt(resnamelength);
980 rr2.put(resname);
981 rr2.putInt(resclassnamelength);
982 rr2.put(resclassname.getBytes());
983 rr2.putInt(xidfi);
984 rr2.putInt(xidgti.length);
985 rr2.put(xidgti);
986 rr2.putInt(xidbq.length);
987 rr2.put(xidbq);
988 rr2.putInt(status);
989
990 if (TraceTm.recovery.isDebugEnabled()) {
991 TraceTm.recovery.debug("Prepare Init RR2 to Recovery Buffer");
992 }
993 recoveryBuffer[i + 1] = rr2.array();
994 }
995
996 try {
997 xaCommitTx = TransactionRecoveryImpl.getTransactionRecovery().howlCommitLog(recoveryBuffer);
998 } catch (Exception e) {
999
1000 status = Status.STATUS_ROLLEDBACK;
1001
1002 String howlerror = "Cannot howlCommitLog:" + e + " --" + e.getMessage();
1003 TraceTm.jotm.error("Got LogException from howlCommitLog: " + howlerror);
1004 xaCommitTx = null;
1005 doAfterCompletion();
1006 log.forgetLog();
1007
1008
1009 throw new JotmTransactionRolledbackException(e);
1010
1011 }
1012 }
1013
1014
1015
1016 status = Status.STATUS_COMMITTING;
1017 if (TraceTm.recovery.isDebugEnabled()) {
1018 TraceTm.recovery.debug("Status Committing");
1019 }
1020
1021
1022
1023 for (int i = 0; i < loggedResources.size(); i++) {
1024 XAResource res = (XAResource) loggedResources.get(i);
1025
1026
1027 javax.transaction.xa.Xid myjavaxxid = (javax.transaction.xa.Xid) loggedJavaxXids.get(i);
1028 Xid xid = (Xid) loggedXids.get(i);
1029
1030
1031
1032
1033
1034 if (TraceTm.jta.isDebugEnabled()) {
1035 TraceTm.jta.debug("xid= " + xid);
1036 TraceTm.jta.debug("myjavaxxid= " + myjavaxxid);
1037 TraceTm.jta.debug("attempting commit with resource= " + res);
1038 }
1039
1040 if (Current.getDefaultRecovery()) {
1041 int rmindex = 99;
1042 byte[] resname = (byte[]) byteloggedResources.get(i);
1043 int resnamelength = resname.length;
1044
1045 String resclassname = res.getClass().getName();
1046 int resclassnamelength = resclassname.length();
1047 int xidfi = xid.getFormatId();
1048 byte[] xidgti = xid.getGlobalTransactionId();
1049 byte[] xidbq = xid.getBranchQualifier();
1050 int rr2gtilen = xidgti.length;
1051 int rr2bqlen = xidbq.length;
1052
1053
1054
1055 recoveryRecord2 = new byte[3 + 4 + 4 + resnamelength + 4 + resclassnamelength + 4 + 4 + rr2gtilen + 4
1056 + rr2bqlen + 4];
1057
1058 rr2 = ByteBuffer.wrap(recoveryRecord2);
1059
1060 rr2.put(RT2);
1061 rr2.putInt(rmindex);
1062 rr2.putInt(resnamelength);
1063 rr2.put(resname);
1064 rr2.putInt(resclassnamelength);
1065 rr2.put(resclassname.getBytes());
1066 rr2.putInt(xidfi);
1067 rr2.putInt(xidgti.length);
1068 rr2.put(xidgti);
1069 rr2.putInt(xidbq.length);
1070 rr2.put(xidbq);
1071 }
1072
1073
1074
1075 try {
1076 res.commit(myjavaxxid, false);
1077
1078
1079 if (Current.getDefaultRecovery()) {
1080 rr2.putInt(Status.STATUS_COMMITTED);
1081 if (TraceTm.recovery.isDebugEnabled()) {
1082 TraceTm.recovery.debug("Status Committed");
1083 }
1084 }
1085
1086 commitnb++;
1087 } catch (XAException e) {
1088 switch (e.errorCode) {
1089 case XAException.XA_HEURHAZ:
1090 case XAException.XA_HEURCOM:
1091 case XAException.XA_HEURRB:
1092 case XAException.XA_HEURMIX:
1093 if (TraceTm.jta.isDebugEnabled()) {
1094 TraceTm.jta.debug("Heuristic condition= " + e.getMessage());
1095 }
1096
1097 if (Current.getDefaultRecovery()) {
1098 rr2.putInt(Status.STATUS_UNKNOWN);
1099 if (TraceTm.recovery.isDebugEnabled()) {
1100 TraceTm.recovery.debug("Status Unknown");
1101 }
1102 }
1103 break;
1104 case XAException.XAER_RMERR:
1105 case XAException.XAER_NOTA:
1106 case XAException.XAER_INVAL:
1107 case XAException.XAER_PROTO:
1108 case XAException.XAER_RMFAIL:
1109 if (TraceTm.jta.isDebugEnabled()) {
1110 TraceTm.jta.debug("RM error= " + e.getMessage());
1111 }
1112
1113 if (Current.getDefaultRecovery()) {
1114 rr2.putInt(Status.STATUS_COMMITTING);
1115 if (TraceTm.recovery.isDebugEnabled()) {
1116 TraceTm.recovery.debug("Status Committing");
1117 }
1118 }
1119 break;
1120 default:
1121 if (TraceTm.jta.isDebugEnabled()) {
1122 TraceTm.jta.debug("Default error= " + e.getMessage());
1123 }
1124
1125 if (Current.getDefaultRecovery()) {
1126 rr2.putInt(Status.STATUS_ROLLEDBACK);
1127 if (TraceTm.recovery.isDebugEnabled()) {
1128 TraceTm.recovery.debug("Status Rolledback");
1129 }
1130 }
1131 }
1132
1133 String error = "Cannot send res.commit:" + e + " (error code = " + e.errorCode + ") --"
1134 + e.getMessage();
1135 TraceTm.jotm.error("Got XAException from res.commit: " + error);
1136
1137 successfulcommit = false;
1138 if (commitnb > 0) {
1139 heuristicnb++;
1140 }
1141 }
1142
1143 if (Current.getDefaultRecovery()) {
1144 if (TraceTm.recovery.isDebugEnabled()) {
1145 TraceTm.recovery.debug("Prepare New RR2 to Recovery Buffer");
1146 }
1147 recoveryBuffer[i + 1] = rr2.array();
1148 }
1149 }
1150
1151 if (successfulcommit) {
1152
1153 Current.getCurrent().incrementCommitCounter();
1154
1155 status = Status.STATUS_COMMITTED;
1156
1157 if (TraceTm.recovery.isDebugEnabled()) {
1158 TraceTm.recovery.debug("Status Committed");
1159 }
1160
1161 if (Current.getDefaultRecovery()) {
1162 try {
1163 if (TraceTm.recovery.isDebugEnabled()) {
1164 TraceTm.recovery.debug("Done howl log, all okay");
1165 }
1166
1167 jotmDoneRecord[0] = JOTMDONE;
1168 TransactionRecoveryImpl.getTransactionRecovery().howlDoneLog(jotmDoneRecord, xaCommitTx);
1169 } catch (Exception f) {
1170 String howlerror = "Cannot howlDoneLog:" + f + "--" + f.getMessage();
1171 TraceTm.jotm.error("Got LogException from howlDoneLog: " + howlerror);
1172 }
1173 }
1174
1175 doAfterCompletion();
1176 log.forgetLog();
1177
1178 if (TraceTm.jta.isDebugEnabled()) {
1179 TraceTm.jta.debug("SubCoordinator.doCommit(): EXIT 0");
1180 }
1181
1182 return 0;
1183 }
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203 if (Current.getDefaultRecovery()) {
1204 try {
1205 if (TraceTm.recovery.isDebugEnabled()) {
1206 TraceTm.recovery.debug("Rewrite HowlCommitLog");
1207 }
1208 xaCommitTxRewrite = TransactionRecoveryImpl.getTransactionRecovery().howlCommitLog(recoveryBuffer);
1209 } catch (Exception e) {
1210
1211 status = Status.STATUS_UNKNOWN;
1212 if (TraceTm.recovery.isDebugEnabled()) {
1213 TraceTm.recovery.debug("Status Unknown");
1214 }
1215
1216 String howlerror = "Cannot howlCommitLog:" + e + " --" + e.getMessage();
1217 TraceTm.jotm.error("Got LogException from howlCommitLog: " + howlerror);
1218 xaCommitTx = null;
1219
1220 doAfterCompletion();
1221 log.forgetLog();
1222
1223 throw new JotmTransactionRolledbackException(e);
1224 }
1225
1226
1227
1228
1229 try {
1230 jotmDoneRecord[0] = JOTMDONE;
1231 TransactionRecoveryImpl.getTransactionRecovery().howlDoneLog(jotmDoneRecord, xaCommitTx);
1232 } catch (Exception f) {
1233 String howlerror = "Cannot howlDoneLog" + f + "--" + f.getMessage();
1234 TraceTm.jotm.error("Got LogException from howlDoneLog: " + howlerror);
1235 }
1236 }
1237
1238
1239 status = Status.STATUS_UNKNOWN;
1240
1241 if (TraceTm.recovery.isDebugEnabled()) {
1242 TraceTm.recovery.debug("Status Unknown");
1243 }
1244
1245 doAfterCompletion();
1246
1247 if (TraceTm.jta.isDebugEnabled()) {
1248 TraceTm.jta.debug("SubCoordinator.doCommit(): Exit -1");
1249 }
1250
1251 return -1;
1252 }
1253
1254
1255
1256
1257 private synchronized void doOnePhaseCommit() throws RemoteException {
1258 if (TraceTm.jta.isDebugEnabled()) {
1259 TraceTm.jta.debug("SubCoordinator.doOnePhaseCommit()");
1260 }
1261
1262
1263
1264 status = Status.STATUS_COMMITTING;
1265
1266 XAResource res = (XAResource) resourceList.elementAt(0);
1267 javax.transaction.xa.Xid myjavaxxid = (javax.transaction.xa.Xid) javaxxidList.elementAt(0);
1268
1269 if (TraceTm.jta.isDebugEnabled()) {
1270 TraceTm.jta.debug("myjavaxxid= " + myjavaxxid);
1271 TraceTm.jta.debug("one phase commit with resource= " + res);
1272 }
1273
1274 try {
1275 res.commit(myjavaxxid, true);
1276
1277
1278 Current.getCurrent().incrementCommitCounter();
1279 status = Status.STATUS_COMMITTED;
1280 } catch (XAException e) {
1281 status = Status.STATUS_UNKNOWN;
1282 String error = "Cannot send res.commit:" + e + " (error code = " + e.errorCode + ") --" + e.getMessage();
1283 TraceTm.jotm.error("Got XAException from res.commit: " + error);
1284
1285 if (e.errorCode == XAException.XA_RBROLLBACK) {
1286
1287 throw new JotmTransactionRolledbackException("XAException:" + error, e);
1288
1289 }
1290 throw new RemoteException("XAException:" + error);
1291 } finally {
1292 doAfterCompletion();
1293 }
1294 }
1295
1296
1297
1298
1299
1300 private synchronized void doRollback() throws RemoteException {
1301 if (TraceTm.jta.isDebugEnabled()) {
1302 TraceTm.jta.debug("SubCoordinator.doRollback()");
1303 }
1304
1305 status = Status.STATUS_ROLLEDBACK;
1306 boolean heurroll = false;
1307 String heuristic = null;
1308
1309
1310 for (int i = 0; i < resourceList.size(); i++) {
1311
1312 XAResource res = (XAResource) resourceList.elementAt(i);
1313 javax.transaction.xa.Xid myjavaxxid = (javax.transaction.xa.Xid) javaxxidList.elementAt(i);
1314
1315 if (TraceTm.jta.isDebugEnabled()) {
1316 TraceTm.jta.debug("myjavaxxid= " + myjavaxxid);
1317 TraceTm.jta.debug("rolled back with resource= " + res);
1318 }
1319
1320
1321
1322
1323
1324 try {
1325 res.rollback(myjavaxxid);
1326 } catch (XAException e) {
1327 switch (e.errorCode) {
1328 case XAException.XA_HEURHAZ:
1329 case XAException.XA_HEURCOM:
1330 case XAException.XA_HEURRB:
1331 case XAException.XA_HEURMIX:
1332 heuristic = "Heuristic condition= " + e.errorCode + "--" + e.getMessage();
1333 TraceTm.jta.warn(heuristic);
1334 heurroll = true;
1335 break;
1336 case XAException.XAER_RMERR:
1337 case XAException.XAER_NOTA:
1338 case XAException.XAER_INVAL:
1339 case XAException.XAER_PROTO:
1340 case XAException.XAER_RMFAIL:
1341 if (TraceTm.jta.isDebugEnabled()) {
1342 TraceTm.jta.debug("RM error= " + e.errorCode + "--" + e.getMessage());
1343 }
1344 break;
1345 default:
1346 if (TraceTm.jta.isDebugEnabled()) {
1347 TraceTm.jta.debug("Default error= " + e.errorCode + "--" + e.getMessage());
1348 }
1349 }
1350 }
1351 }
1352
1353
1354
1355
1356
1357 if (heurroll) {
1358
1359 throw new HeuristicRollback(heuristic);
1360 }
1361
1362
1363
1364 Current.getCurrent().incrementRollbackCounter();
1365
1366 doAfterCompletion();
1367 }
1368
1369
1370
1371
1372
1373
1374 private void doBeforeCompletion(boolean committing) {
1375 if (TraceTm.jta.isDebugEnabled()) {
1376 TraceTm.jta.debug("doBeforeCompletion committing= " + committing);
1377 }
1378 if (beforeCompletionDone) {
1379 return;
1380 }
1381
1382
1383 tx.unsetTimer();
1384
1385
1386
1387 if (committing && synchroList.size() > 0) {
1388
1389
1390
1391
1392
1393
1394 Transaction mytx = null;
1395 boolean suspended = false;
1396 boolean resumed = false;
1397
1398 try {
1399 mytx = tm.getTransaction();
1400 } catch (SystemException e) {
1401 if (TraceTm.jta.isDebugEnabled()) {
1402 String error = "Cannot get transaction:" + e + "--" + e.getMessage();
1403 TraceTm.jta.debug(error);
1404 }
1405 }
1406
1407
1408
1409 if (mytx != null && mytx.equals(tx) == false) {
1410 try {
1411 tm.suspend();
1412 suspended = true;
1413 } catch (SystemException e) {
1414 if (TraceTm.jta.isDebugEnabled()) {
1415 String error = "Cannot suspend transaction:" + e + "--" + e.getMessage();
1416 TraceTm.jta.debug(error);
1417 }
1418 }
1419 }
1420
1421
1422
1423 if (mytx == null || suspended) {
1424 try {
1425 tm.resume(tx);
1426 resumed = true;
1427 } catch (SystemException e) {
1428 if (TraceTm.jta.isDebugEnabled()) {
1429 String error = "Cannot resume transaction:" + e + "--" + e.getMessage();
1430 TraceTm.jta.debug(error);
1431 }
1432 } catch (InvalidTransactionException e) {
1433 if (TraceTm.jta.isDebugEnabled()) {
1434 String error = "Cannot resume transaction:" + e + "--" + e.getMessage();
1435 TraceTm.jta.debug(error);
1436 }
1437 } catch (IllegalStateException e) {
1438 if (TraceTm.jta.isDebugEnabled()) {
1439 String error = "Cannot resume transaction:" + e + "--" + e.getMessage();
1440 TraceTm.jta.debug(error);
1441 }
1442 }
1443 }
1444
1445
1446
1447
1448 if (TraceTm.jta.isDebugEnabled()) {
1449 TraceTm.jta.debug("sychronization list size= " + synchroList.size());
1450 }
1451
1452 for (int i = 0; i < synchroList.size(); i++) {
1453 Synchronization sync = (Synchronization) synchroList.elementAt(i);
1454
1455 if (TraceTm.jta.isDebugEnabled()) {
1456 TraceTm.jta.debug("Calling Synchro " + sync);
1457 }
1458
1459 try {
1460
1461
1462
1463 sync.beforeCompletion();
1464 } catch (RuntimeException e) {
1465 status = Status.STATUS_MARKED_ROLLBACK;
1466 rollbackCause = e;
1467 if (TraceTm.jta.isDebugEnabled()) {
1468 String error = "Cannot sync.beforeCompletion:" + e + "--" + e.getMessage();
1469 TraceTm.jta.debug(error);
1470 }
1471 }
1472 }
1473
1474
1475
1476 if (resumed) {
1477 try {
1478 tm.suspend();
1479 } catch (SystemException e) {
1480 if (TraceTm.jta.isDebugEnabled()) {
1481 String error = "Cannot suspend transaction:" + e + "--" + e.getMessage();
1482 TraceTm.jta.debug(error);
1483 }
1484 }
1485 }
1486
1487 if (suspended) {
1488 try {
1489 tm.resume(mytx);
1490 resumed = true;
1491 } catch (SystemException e) {
1492 if (TraceTm.jta.isDebugEnabled()) {
1493 String error = "Cannot resume transaction:" + e + "--" + e.getMessage();
1494 TraceTm.jta.debug(error);
1495 }
1496 } catch (InvalidTransactionException e) {
1497 if (TraceTm.jta.isDebugEnabled()) {
1498 String error = "Cannot resume transaction:" + e + "--" + e.getMessage();
1499 TraceTm.jta.debug(error);
1500 }
1501 } catch (IllegalStateException e) {
1502 if (TraceTm.jta.isDebugEnabled()) {
1503 String error = "Cannot resume transaction:" + e + "--" + e.getMessage();
1504 TraceTm.jta.debug(error);
1505 }
1506 }
1507 }
1508 }
1509
1510 beforeCompletionDone = true;
1511 }
1512
1513
1514
1515
1516 private void doAfterCompletion() {
1517 if (TraceTm.jta.isDebugEnabled()) {
1518 TraceTm.jta.debug("doAfterCompletion()");
1519 }
1520
1521
1522
1523
1524 if (TraceTm.jta.isDebugEnabled()) {
1525 TraceTm.jta.debug("sychronization list size= " + synchroList.size());
1526 }
1527
1528 for (int i = 0; i < synchroList.size(); i++) {
1529 Synchronization sync = (Synchronization) synchroList.elementAt(i);
1530
1531 if (TraceTm.jta.isDebugEnabled()) {
1532 TraceTm.jta.debug("Synchronization sync= " + sync);
1533 TraceTm.jta.debug("sync.afterCompletion status= " + StatusHelper.getStatusName(status));
1534 }
1535
1536 sync.afterCompletion(status);
1537 }
1538
1539
1540
1541
1542
1543 Current.getCurrent().forgetTx(tx.getXid());
1544 }
1545
1546
1547
1548
1549
1550
1551
1552
1553 public int getXaresIndex(XAResource xares) {
1554
1555 if (TraceTm.jta.isDebugEnabled()) {
1556 TraceTm.jta.debug("getXaresIndex xares= " + xares);
1557 TraceTm.jta.debug("resourceList.size= " + resourceList.size());
1558 }
1559
1560 int xaresIndex = -1;
1561
1562
1563 if (TraceTm.jta.isDebugEnabled()) {
1564 TraceTm.jta.debug("search xares with same obj ref");
1565 }
1566
1567 for (int i = 0; i < resourceList.size(); i++) {
1568 XAResource res = (XAResource) resourceList.elementAt(i);
1569
1570 if (TraceTm.jta.isDebugEnabled()) {
1571 TraceTm.jta.debug("res= " + res);
1572 }
1573
1574 if (res.equals(xares)) {
1575 xaresIndex = i;
1576 break;
1577 }
1578 }
1579
1580
1581 if (xaresIndex == -1) {
1582 if (TraceTm.jta.isDebugEnabled()) {
1583 TraceTm.jta.debug("not found -> search for xares with same RM");
1584 }
1585
1586 for (int i = 0; i < resourceList.size(); i++) {
1587 XAResource res = (XAResource) resourceList.elementAt(i);
1588
1589 if (TraceTm.jta.isDebugEnabled()) {
1590 TraceTm.jta.debug("res= " + res);
1591 }
1592
1593 try {
1594 if (res.isSameRM(xares)) {
1595 xaresIndex = i;
1596 break;
1597 }
1598 } catch (XAException e) {
1599 if (TraceTm.jta.isDebugEnabled()) {
1600 String error = "res.isSameRm exception:" + e + "--" + e.getMessage();
1601 TraceTm.jta.debug(error);
1602 }
1603 }
1604 }
1605 }
1606
1607 if (TraceTm.jta.isDebugEnabled()) {
1608 TraceTm.jta.debug("xaresIndex= " + xaresIndex);
1609 }
1610
1611 return xaresIndex;
1612 }
1613
1614 }