1 22 package org.jboss.tm; 23 24 import java.lang.reflect.Proxy ; 25 import java.rmi.NoSuchObjectException ; 26 import java.rmi.RemoteException ; 27 import java.util.ArrayList ; 28 import java.util.Collections ; 29 import java.util.HashMap ; 30 import java.util.HashSet ; 31 import java.util.Iterator ; 32 import java.util.List ; 33 import java.util.Map ; 34 import java.util.Set ; 35 36 import javax.resource.spi.work.Work ; 37 import javax.resource.spi.work.WorkCompletedException ; 38 import javax.resource.spi.work.WorkException ; 39 import javax.transaction.HeuristicCommitException ; 40 import javax.transaction.HeuristicMixedException ; 41 import javax.transaction.HeuristicRollbackException ; 42 import javax.transaction.RollbackException ; 43 import javax.transaction.Status ; 44 import javax.transaction.Synchronization ; 45 import javax.transaction.SystemException ; 46 import javax.transaction.Transaction ; 47 import javax.transaction.TransactionRolledbackException ; 48 import javax.transaction.xa.XAException ; 49 import javax.transaction.xa.XAResource ; 50 import javax.transaction.xa.Xid ; 51 52 import org.jboss.logging.Logger; 53 import org.jboss.tm.integrity.TransactionIntegrity; 54 import org.jboss.tm.recovery.HeuristicStatus; 55 import org.jboss.tm.recovery.LogRecord; 56 import org.jboss.tm.recovery.RecoveryLogger; 57 import org.jboss.tm.recovery.RecoveryTestingException; 58 import org.jboss.tm.recovery.TxCompletionHandler; 59 import org.jboss.tm.recovery.XAResourceAccess; 60 import org.jboss.tm.recovery.XAWork; 61 import org.jboss.tm.remoting.interfaces.Coordinator; 62 import org.jboss.tm.remoting.interfaces.HeuristicHazardException; 63 import org.jboss.tm.remoting.interfaces.RecoveryCoordinator; 64 import org.jboss.tm.remoting.interfaces.Resource; 65 import org.jboss.tm.remoting.interfaces.TransactionAlreadyPreparedException; 66 import org.jboss.tm.remoting.interfaces.TransactionInactiveException; 67 import org.jboss.tm.remoting.interfaces.TransactionNotPreparedException; 68 import org.jboss.tm.remoting.interfaces.TxPropagationContext; 69 import org.jboss.tm.remoting.interfaces.Vote; 70 import org.jboss.util.timeout.Timeout; 71 import org.jboss.util.timeout.TimeoutFactory; 72 import org.jboss.util.timeout.TimeoutTarget; 73 74 90 public class TransactionImpl 91 implements Transaction , TimeoutTarget 92 { 93 95 99 private static final int HEUR_NONE = 0; 100 101 105 private static final int HEUR_UNKNOWN = XAException.XA_RETRY; 106 107 private final static int RS_NEW = 0; private final static int RS_ENLISTED = 1; private final static int RS_SUSPENDED = 2; private final static int RS_ENDED = 3; private final static int RS_VOTE_READONLY = 4; private final static int RS_VOTE_OK = 5; private final static int RS_FORGOT = 6; private final static int RS_COMMITTED = 7; private final static int RS_ROLLEDBACK = 8; private final static int RS_HEUR_OUTCOME = 8; private final static int RS_ERROR = 9; 120 122 125 private boolean trace = log.isTraceEnabled(); 126 127 130 private XidImpl xid; 131 132 private HashSet threads = new HashSet (1); 133 134 private Map transactionLocalMap = Collections.synchronizedMap(new HashMap ()); 135 136 private Throwable cause; 137 138 143 private final boolean foreignTx; 144 145 151 private Coordinator parentCoordinator = null; 152 153 156 private Resource registeredResource = null; 157 158 162 private RecoveryCoordinator recoveryCoordinator = null; 163 164 168 private byte[] inboundBranchQualifier = null; 169 170 173 private Synchronization [] sync = new Synchronization [3]; 174 175 178 private int syncAllocSize = 3; 179 180 183 private int syncCount = 0; 184 185 188 private ArrayList xaResources = new ArrayList (3); 189 190 193 private ArrayList remoteResources = new ArrayList (3); 194 195 198 private EnlistedXAResource lastResource; 199 200 203 private boolean resourcesEnded = false; 204 205 208 private long lastBranchId = 0; 209 210 213 private int status; 214 215 218 private int heuristicCode = HEUR_NONE; 219 220 223 private long start; 224 225 228 private Timeout timeout; 229 230 233 private long timeoutPeriod; 234 235 239 private Thread locked = null; 240 241 244 private int lockDepth = 0; 245 246 249 private Work work; 250 251 254 private boolean done = false; 255 256 259 private TxPropagationContext dtmPropagationContext = null; 260 261 264 private Object otsPropagationContext = null; 265 266 269 private TxCompletionHandler completionHandler = null; 270 271 274 private int xaResourcesToRetry = 0; 275 276 279 private int remoteResourcesToRetry = 0; 280 281 285 private Timeout preparedTimeout = null; 286 287 291 private Timeout xaRetryTimeout = null; 292 293 297 private List xaResourcesWithHeuristicDecisions = null; 298 299 303 private List remoteResourcesWithHeuristicDecisions = null; 304 305 308 private int committedResources = 0; 309 310 313 private int rolledbackResources = 0; 314 315 319 private boolean heuristicHazard = false; 320 321 323 326 private static Logger log = Logger.getLogger(TransactionImpl.class); 327 328 333 static XidFactoryBase xidFactory; 334 335 static XAExceptionFormatter xaExceptionFormatter; 336 337 338 static TimeoutFactory timeoutFactory = TimeoutFactory.getSingleton(); 339 340 344 private static CoordinatorFactory dtmCoordinatorFactory = null; 345 346 350 private static ResourceFactory dtmResourceFactory = null; 351 352 356 private static ResourceFactory otsResourceFactory = null; 357 358 362 private static OTSContextFactory otsContextFactory = null; 363 364 367 private static boolean interpositionEnabled = false; 368 369 373 private static StringRemoteRefConverter dtmStrRemoteRefConverter = null; 374 375 379 private static StringRemoteRefConverter otsStrRemoteRefConverter = null; 380 381 385 public static XidFactoryBase defaultXidFactory() 386 { 387 if (xidFactory == null) 388 { 389 XidFactoryImpl impl = new XidFactoryImpl(); 390 impl.start(); 391 xidFactory = impl; 392 } 393 return xidFactory; 394 } 395 396 399 static void setDTMCoordinatorFactory(CoordinatorFactory dtmCoordinatorFactory) 400 { 401 TransactionImpl.dtmCoordinatorFactory = dtmCoordinatorFactory; 402 } 403 404 407 static void setDTMResourceFactory(ResourceFactory dtmResourceFactory) 408 { 409 TransactionImpl.dtmResourceFactory = dtmResourceFactory; 410 } 411 412 415 static void setOTSResourceFactory(ResourceFactory otsResourceFactory) 416 { 417 TransactionImpl.otsResourceFactory = otsResourceFactory; 418 } 419 420 423 static void setOTSContextFactory(OTSContextFactory otsContextFactory) 424 { 425 TransactionImpl.otsContextFactory = otsContextFactory; 426 } 427 428 431 static void setInterpositionEnabled(boolean interpositionEnabled) 432 { 433 TransactionImpl.interpositionEnabled = interpositionEnabled; 434 } 435 436 439 static boolean getInterpositionEnabled() 440 { 441 return TransactionImpl.interpositionEnabled; 442 } 443 444 447 static void setDTMStrRemoteRefConverter( 448 StringRemoteRefConverter dtmStrRemoteRefConverter) 449 { 450 TransactionImpl.dtmStrRemoteRefConverter = dtmStrRemoteRefConverter; 451 } 452 453 456 static void setOTSStrRemoteRefConverter( 457 StringRemoteRefConverter otsStrRemoteRefConverter) 458 { 459 TransactionImpl.otsStrRemoteRefConverter = otsStrRemoteRefConverter; 460 } 461 462 469 static Resource stringToResource(String strResource) 470 { 471 if (strResource.startsWith("IOR:")) 472 { 473 if (otsStrRemoteRefConverter != null) 474 return otsStrRemoteRefConverter.stringToResource(strResource); 475 else 476 throw new IllegalArgumentException (); 477 } 478 else 479 { 480 if (dtmStrRemoteRefConverter != null) 481 return dtmStrRemoteRefConverter.stringToResource(strResource); 482 else 483 throw new IllegalArgumentException (); 484 } 485 } 486 487 495 static RecoveryCoordinator stringToRecoveryCoordinator( 496 String strRecCoordinator) 497 { 498 if (strRecCoordinator.startsWith("IOR:")) 499 { 500 if (otsStrRemoteRefConverter != null) 501 return otsStrRemoteRefConverter.stringToRecoveryCoordinator( 502 strRecCoordinator); 503 else 504 throw new IllegalArgumentException (); 505 } 506 else 507 { 508 if (dtmStrRemoteRefConverter != null) 509 return dtmStrRemoteRefConverter.stringToRecoveryCoordinator( 510 strRecCoordinator); 511 else 512 throw new IllegalArgumentException (); 513 } 514 } 515 516 522 static String resourceToString(Resource res) 523 { 524 if (Proxy.isProxyClass(res.getClass())) 525 { 526 if (dtmStrRemoteRefConverter != null) 527 return dtmStrRemoteRefConverter.resourceToString(res); 528 else 529 throw new IllegalArgumentException (); 530 } 531 else 532 { 533 if (otsStrRemoteRefConverter != null) 534 return otsStrRemoteRefConverter.resourceToString(res); 535 else 536 throw new IllegalArgumentException (); 537 } 538 } 539 540 547 static String recoveryCoordinatorToString(RecoveryCoordinator recoveryCoord) 548 { 549 if (Proxy.isProxyClass(recoveryCoord.getClass())) 550 { 551 if (dtmStrRemoteRefConverter != null) 552 return dtmStrRemoteRefConverter.recoveryCoordinatorToString( 553 recoveryCoord); 554 else 555 throw new IllegalArgumentException (); 556 } 557 else 558 { 559 if (otsStrRemoteRefConverter != null) 560 return otsStrRemoteRefConverter.recoveryCoordinatorToString( 561 recoveryCoord); 562 else 563 throw new IllegalArgumentException (); 564 } 565 } 566 567 569 572 TransactionImpl(long timeout) 573 { 574 foreignTx = false; 575 xid = xidFactory.newXid(); 576 577 status = Status.STATUS_ACTIVE; 578 579 start = System.currentTimeMillis(); 580 this.timeout = timeoutFactory.createTimeout(start + timeout, this); 581 this.timeoutPeriod = timeout; 582 if (trace) 583 log.trace("Created new instance for tx=" + toString()); 584 } 585 586 590 TransactionImpl(GlobalId gid, Coordinator parentCoordinator, long timeout) 591 { 592 foreignTx = true; 593 xid = xidFactory.newBranch(gid); 594 595 this.parentCoordinator = parentCoordinator; 596 597 status = Status.STATUS_ACTIVE; 598 599 start = System.currentTimeMillis(); 600 this.timeout = timeoutFactory.createTimeout(start + timeout, this); 601 this.timeoutPeriod = timeout; 602 if (trace) 603 log.trace("Created new instance for tx=" + toString()); 604 } 605 606 610 TransactionImpl(GlobalId gid, byte[] inboundBranchQualifier, long timeout) 611 { 612 foreignTx = true; 613 xid = xidFactory.newBranch(gid); 614 615 this.inboundBranchQualifier = inboundBranchQualifier; 616 617 status = Status.STATUS_ACTIVE; 618 619 start = System.currentTimeMillis(); 620 this.timeout = timeoutFactory.createTimeout(start + timeout, this); 621 this.timeoutPeriod = timeout; 622 if (trace) 623 log.trace("Created new instance for tx=" + toString()); 624 625 } 626 627 648 TransactionImpl(long localId, 649 List preparedXAWorkList, 650 TxCompletionHandler completionHandler, 651 LogRecord.HeurData heurData) 652 { 653 foreignTx = false; 654 xid = xidFactory.recreateXid(localId); 655 status = Status.STATUS_COMMITTING; 656 if (heurData != null) 657 { 658 heuristicCode = heurData.heuristicStatusCode; 659 heuristicHazard = heurData.locallyDetectedHeuristicHazard; 660 } 661 this.completionHandler = completionHandler; 662 for (Iterator it = preparedXAWorkList.iterator(); it.hasNext(); ) 663 { 664 XAWork preparedXAWork = (XAWork) it.next(); 665 EnlistedXAResource r = new EnlistedXAResource(preparedXAWork); 666 xaResources.add(r); 667 668 } 669 commitXAResourcesAfterTimeout(); 670 } 671 672 697 TransactionImpl(long localId, 698 List preparedXAWorkList, 699 String [] resources, 700 TxCompletionHandler completionHandler, 701 LogRecord.HeurData heurData) 702 { 703 foreignTx = false; 704 xid = xidFactory.recreateXid(localId); 705 status = Status.STATUS_COMMITTING; 706 this.completionHandler = completionHandler; 707 if (heurData != null) 708 { 709 heuristicCode = heurData.heuristicStatusCode; 710 heuristicHazard = heurData.locallyDetectedHeuristicHazard; 711 } 712 for (Iterator it = preparedXAWorkList.iterator(); it.hasNext(); ) 713 { 714 XAWork preparedXAWork = (XAWork) it.next(); 715 EnlistedXAResource r = new EnlistedXAResource(preparedXAWork); 716 xaResources.add(r); 717 } 718 for (int i = 0; i < resources.length; i++) 719 { 720 EnlistedRemoteResource r = 721 new EnlistedRemoteResource(stringToResource(resources[i]), true); 722 remoteResources.add(r); 723 } 724 lock(); 725 try 726 { 727 retryCommitRemoteResources(); 728 } 729 finally 730 { 731 unlock(); 732 } 733 if (preparedXAWorkList.size() > 0) 734 { 735 commitXAResourcesAfterTimeout(); 738 } 739 else if (remoteResourcesToRetry == 0 && heuristicCode == HEUR_NONE) 740 { 741 lock(); 743 try 744 { 745 completeTransaction(); 746 } 747 finally 748 { 749 unlock(); 750 } 751 } 752 else 753 { 754 } 757 } 758 759 787 TransactionImpl(long localId, 788 int inboundFormatId, 789 byte[] globalTransactionId, 790 String recoveryCoord, 791 List preparedXAWorkList, 792 String [] resources, 793 TxCompletionHandler completionHandler, 794 LogRecord.HeurData heurData) 795 { 796 foreignTx = true; 797 GlobalId globalId = new GlobalId(inboundFormatId, globalTransactionId); 798 xid = xidFactory.recreateXid(localId, globalId); 799 recoveryCoordinator = stringToRecoveryCoordinator(recoveryCoord); 800 if (heurData == null) 801 status = Status.STATUS_PREPARED; 802 else 803 { 804 status = heurData.transactionStatus; 805 heuristicCode = heurData.heuristicStatusCode; 806 heuristicHazard = heurData.locallyDetectedHeuristicHazard; 807 } 808 this.completionHandler = completionHandler; 809 for (Iterator it = preparedXAWorkList.iterator(); it.hasNext(); ) 810 { 811 XAWork preparedXAWork = (XAWork) it.next(); 812 EnlistedXAResource r = new EnlistedXAResource(preparedXAWork); 813 xaResources.add(r); 814 } 815 for (int i = 0; i < resources.length; i++) 816 { 817 EnlistedRemoteResource r = 818 new EnlistedRemoteResource(stringToResource(resources[i]), true); 819 remoteResources.add(r); 820 } 821 822 if (Proxy.isProxyClass(recoveryCoordinator.getClass())) 824 { 825 if (dtmResourceFactory != null) 827 registeredResource = dtmResourceFactory.createResource(localId); 828 else 829 log.warn("Error reconstructing TransactionImpl instance for tx=" 830 + toString() + " -- DTM resource factory missing." ); 831 } 832 else 833 { 834 if (otsResourceFactory != null) 836 registeredResource = otsResourceFactory.createResource(localId); 837 else 838 log.warn("Error reconstructing TransactionImpl instance for tx=" + 839 toString() + " -- OTS resource factory missing." ); 840 } 841 842 if (status == Status.STATUS_PREPARED) 843 { 844 if (registeredResource != null) 845 { 846 createPreparedTimeout(); 847 if (trace) 848 log.trace("Calling replayCompletion " + 849 "on the recovery coordinator, tx=" + toString()); 850 try 851 { 852 recoveryCoordinator.replayCompletion(registeredResource); 853 } 854 catch (NoSuchObjectException noCoordinator) 855 { 856 if (trace) 857 { 858 log.trace("Exception in replayCompletion: no coordinator for tx=" 859 + toString(), noCoordinator); 860 log.trace("Rolling back transaction branch, tx=" + toString()); 861 } 862 try 863 { 864 rollbackBranch(); 865 } 866 catch (Exception e) 867 { 868 if (trace) 869 log.trace("Exception in transaction branch rollback, tx=" + 870 toString(), e); 871 } 872 } 873 catch (Exception ignore) 874 { 875 if (trace) 876 log.trace("Ignoring exception in replayCompletion, tx=" + 877 toString(), ignore); 878 } 879 } 880 else 881 log.warn("Error reconstructing TransactionImpl instance for tx=" + 882 toString() + " -- registeredResource not set.\n" + 883 "The remote coordinator will NOT be contacted."); 884 } 885 else if (status == Status.STATUS_COMMITTING) 886 { 887 lock(); 888 try 889 { 890 retryCommitRemoteResources(); 891 892 if (preparedXAWorkList.size() > 0) 893 { 894 commitXAResourcesAfterTimeout(); 897 } 898 else if (remoteResourcesToRetry == 0 && heuristicCode == HEUR_NONE) 899 { 900 completeTransaction(); 902 } 903 else 904 { 905 } 908 } 909 finally 910 { 911 unlock(); 912 } 913 } 914 else if (status == Status.STATUS_ROLLING_BACK) 915 { 916 try 917 { 918 rollbackResourcesAndCompleteTransaction(); 919 } 920 finally 921 { 922 unlock(); 923 } 924 } 925 } 926 927 952 TransactionImpl(long localId, 953 int inboundFormatId, 954 byte[] globalTransactionId, 955 byte[] inboundBranchQualifier, 956 List preparedXAWorkList, 957 String [] resources, 958 TxCompletionHandler completionHandler, 959 LogRecord.HeurData heurData) 960 { 961 foreignTx = true; 962 GlobalId globalId = new GlobalId(inboundFormatId, globalTransactionId); 963 xid = xidFactory.recreateXid(localId, globalId); 964 if (heurData == null) 965 status = Status.STATUS_PREPARED; 966 else 967 { 968 status = heurData.transactionStatus; 969 heuristicCode = heurData.heuristicStatusCode; 970 heuristicHazard = heurData.locallyDetectedHeuristicHazard; 971 } 972 this.inboundBranchQualifier = inboundBranchQualifier; 973 this.completionHandler = completionHandler; 974 975 for (Iterator it = preparedXAWorkList.iterator(); it.hasNext(); ) 976 { 977 XAWork preparedXAWork = (XAWork) it.next(); 978 EnlistedXAResource r = new EnlistedXAResource(preparedXAWork); 979 xaResources.add(r); 980 } 981 982 for (int i = 0; i < resources.length; i++) 983 { 984 EnlistedRemoteResource resource = 985 new EnlistedRemoteResource(stringToResource(resources[i]), true); 986 remoteResources.add(resource); 987 } 988 989 if (status == Status.STATUS_COMMITTING) 990 { 991 lock(); 992 try 993 { 994 retryCommitRemoteResources(); 995 996 if (xaResourcesToRetry > 0) 997 { 998 commitXAResourcesAfterTimeout(); 1001 } 1002 else if (remoteResourcesToRetry == 0 && heuristicCode == HEUR_NONE) 1003 { 1004 completeTransaction(); 1006 } 1007 else 1008 { 1009 } 1012 } 1013 finally 1014 { 1015 unlock(); 1016 } 1017 } 1018 else if (status == Status.STATUS_ROLLING_BACK) 1019 { 1020 try 1021 { 1022 rollbackResourcesAndCompleteTransaction(); 1023 } 1024 finally 1025 { 1026 unlock(); 1027 } 1028 } 1029 } 1030 1031 1048 TransactionImpl(LogRecord.HeurData heurData, 1049 List xaResourcesWithHeuristics, 1050 TxCompletionHandler completionHandler) 1051 { 1052 foreignTx = heurData.foreignTx; 1053 status = heurData.transactionStatus; 1054 1055 if (status != Status.STATUS_COMMITTING && 1056 status != Status.STATUS_COMMITTED && 1057 status != Status.STATUS_ROLLING_BACK && 1058 status != Status.STATUS_ROLLEDBACK) 1059 throw new RuntimeException ("Attempt to recreate heuristically " + 1060 "completed transaction with status " + 1061 TxUtils.getStatusAsString(status) + ". " + 1062 "Must be STATUS_COMMITTING, " + 1063 "STATUS_COMMITTED, STATUS_ROLLING_BACK, " + 1064 "or STATUS_ROLLEDBACK."); 1065 if (!foreignTx) 1066 xid = xidFactory.recreateXid(heurData.localTransactionId); 1067 else 1068 { 1069 GlobalId globalId = new GlobalId(heurData.formatId, 1070 heurData.globalTransactionId); 1071 xid = xidFactory.recreateXid(heurData.localTransactionId, globalId); 1072 } 1073 inboundBranchQualifier = heurData.inboundBranchQualifier; 1074 this.completionHandler = completionHandler; 1075 heuristicCode = heurData.heuristicStatusCode; 1076 if (!xaResourcesWithHeuristics.isEmpty()) 1077 { 1078 xaResourcesWithHeuristicDecisions = new ArrayList (); 1079 for (Iterator it = xaResourcesWithHeuristics.iterator(); 1080 it.hasNext(); ) 1081 { 1082 XAWork xaWork = (XAWork) it.next(); 1083 xaWork.xaResourceAccess.release(); 1084 EnlistedXAResource r = new EnlistedXAResource( 1085 xaWork.res, 1086 xaWork.xid, 1087 (heurData.transactionStatus == Status.STATUS_COMMITTED)); 1088 xaResources.add(r); 1089 xaResourcesWithHeuristicDecisions.add(r); 1090 } 1091 } 1092 if (heurData.remoteResourceHeuristics != null && 1093 heurData.remoteResourceHeuristics.length > 0) 1094 { 1095 remoteResourcesWithHeuristicDecisions = new ArrayList (); 1096 for (int i = 0; i < heurData.remoteResourceHeuristics.length; i++) 1097 { 1098 HeuristicStatus heurStatus = heurData.remoteResourceHeuristics[i]; 1099 EnlistedRemoteResource r = 1100 new EnlistedRemoteResource( 1101 stringToResource(heurStatus.resourceRef), 1102 true, 1103 heurStatus.code); 1104 remoteResources.add(r); 1105 remoteResourcesWithHeuristicDecisions.add(r); 1106 } 1107 } 1108 } 1109 1110 1118 public boolean isImported() 1119 { 1120 return foreignTx; 1121 } 1122 1123 1125 1128 public void timedOut(Timeout timeout) 1129 { 1130 lock(); 1131 try 1132 { 1133 log.warn("Transaction " + toString() + " timed out." + 1134 " status=" + TxUtils.getStatusAsString(status)); 1135 1136 if (this.timeout == null) 1137 return; this.timeout = null; 1139 1140 switch (status) 1141 { 1142 case Status.STATUS_ROLLEDBACK: 1143 case Status.STATUS_COMMITTED: 1144 case Status.STATUS_NO_TRANSACTION: 1145 return; 1147 case Status.STATUS_ROLLING_BACK: 1148 return; 1150 case Status.STATUS_PREPARED: 1151 case Status.STATUS_COMMITTING: 1152 return; 1154 case Status.STATUS_ACTIVE: 1155 status = Status.STATUS_MARKED_ROLLBACK; 1156 case Status.STATUS_MARKED_ROLLBACK: 1158 interruptThreads(); 1160 return; 1161 1162 case Status.STATUS_PREPARING: 1163 status = Status.STATUS_MARKED_ROLLBACK; 1164 return; 1166 default: 1167 log.warn("Unknown status at timeout, tx=" + toString()); 1168 return; 1169 } 1170 } 1171 finally 1172 { 1173 unlock(); 1174 } 1175 } 1176 1177 1179 public void commit() 1180 throws RollbackException , 1181 HeuristicMixedException , 1182 HeuristicRollbackException , 1183 java.lang.SecurityException , 1184 java.lang.IllegalStateException , 1185 SystemException 1186 { 1187 lock(); 1188 try 1189 { 1190 if (trace) 1191 log.trace("Committing, tx=" + toString() + 1192 ", status=" + TxUtils.getStatusAsString(status)); 1193 1194 beforePrepare(); 1195 1196 if (status == Status.STATUS_ACTIVE) 1197 { 1198 switch (getCommitStrategy()) 1199 { 1200 case 0: 1201 if (trace) 1203 log.trace("Zero phase commit " + toString() + 1204 ": No resources."); 1205 status = Status.STATUS_COMMITTED; 1206 break; 1207 case 1: 1208 if (trace) 1210 log.trace("One phase commit " + toString() + 1211 ": One resource."); 1212 commitResources(true); 1213 break; 1214 default: 1215 if (trace) 1217 log.trace("Two phase commit " + toString() + 1218 ": Many resources."); 1219 1220 if (!prepareResources()) 1221 { 1222 boolean commitDecision = 1223 status == Status.STATUS_PREPARED && 1224 (heuristicCode == HEUR_NONE || 1225 heuristicCode == XAException.XA_HEURCOM); 1226 1227 if (commitDecision) 1228 { 1229 try 1232 { 1233 RecoveryLogger logger = 1234 TxManager.getInstance().getRecoveryLogger(); 1235 if (logger != null) 1236 { 1237 completionHandler = logger.saveCommitDecision( 1238 xid.getLocalIdValue(), 1239 getStringfiedRemoteResourcesThatVotedCommit()); 1240 } 1241 } 1242 catch (Throwable e) 1243 { 1244 if (e instanceof RecoveryTestingException) 1245 throw (RecoveryTestingException) e; 1246 log.warn("FAILED WHEN WRITING COMMIT RECORD." 1247 + " Rolling back now.", e); 1248 status = Status.STATUS_MARKED_ROLLBACK; 1249 cause = e; 1250 } 1251 cancelTimeout(); 1252 if (status == Status.STATUS_PREPARED) 1253 { 1254 try 1255 { 1256 commitResources(false); 1257 } 1258 catch (Throwable e) 1259 { 1260 if (e instanceof RecoveryTestingException) 1261 throw (RecoveryTestingException) e; 1262 log.warn("Unexpected exception in commitResources:", 1263 e); 1264 } 1265 } 1266 } 1267 } 1268 else 1269 status = Status.STATUS_COMMITTED; } 1271 } 1272 1273 if (status == Status.STATUS_COMMITTING) 1274 { 1275 if (xaResourcesToRetry > 0) 1277 commitXAResourcesAfterTimeout(); 1278 checkHeuristicsButDoNotThrowHeuristicHazard(); 1279 } 1280 else if (status != Status.STATUS_COMMITTED) 1281 { 1282 Throwable causedByThrowable = cause; 1283 rollbackResourcesAndCompleteTransaction(); 1284 1285 throw new JBossRollbackException("Unable to commit, tx=" + 1287 toString() + ", status=" + 1288 TxUtils.getStatusAsString(status), 1289 causedByThrowable); 1290 } 1291 else 1292 { 1293 cancelTimeout(); 1294 doAfterCompletion(); 1295 checkHeuristicsButDoNotThrowHeuristicHazard(); 1296 instanceDone(); 1297 1298 if (trace) 1299 log.trace("Committed OK, tx=" + toString()); 1300 } 1301 } 1302 finally 1303 { 1304 unlock(); 1305 } 1306 } 1307 1308 public void rollback() 1309 throws java.lang.IllegalStateException , 1310 java.lang.SecurityException , 1311 SystemException 1312 { 1313 lock(); 1314 try 1315 { 1316 1317 if (trace) 1318 log.trace("rollback(): Entered, tx=" + toString() + 1319 ", status=" + TxUtils.getStatusAsString(status)); 1320 1321 checkWork(); 1322 1323 switch (status) 1324 { 1325 case Status.STATUS_ACTIVE: 1326 status = Status.STATUS_MARKED_ROLLBACK; 1327 case Status.STATUS_MARKED_ROLLBACK: 1329 endResources(); 1330 rollbackResourcesAndCompleteTransaction(); 1331 heuristicCode = HEUR_NONE; 1334 return; 1335 case Status.STATUS_PREPARING: 1336 status = Status.STATUS_MARKED_ROLLBACK; 1338 return; default: 1340 throw new IllegalStateException ("Cannot rollback(), tx=" + 1341 toString() + ", status=" + 1342 TxUtils.getStatusAsString(status)); 1343 } 1344 } 1345 finally 1346 { 1347 Thread.interrupted(); unlock(); 1349 } 1350 } 1351 1352 public boolean delistResource(XAResource xaRes, int flag) 1353 throws java.lang.IllegalStateException , 1354 SystemException 1355 { 1356 if (xaRes == null) 1357 throw new IllegalArgumentException ("null xaRes tx=" + toString()); 1358 if (flag != XAResource.TMSUCCESS && 1359 flag != XAResource.TMSUSPEND && 1360 flag != XAResource.TMFAIL) 1361 throw new IllegalArgumentException ("Bad flag: " + flag + 1362 " tx=" + toString()); 1363 1364 lock(); 1365 try 1366 { 1367 if (trace) 1368 log.trace("delistResource(): Entered, tx=" + toString() + 1369 ", status=" + TxUtils.getStatusAsString(status)); 1370 1371 EnlistedXAResource resource = findResource(xaRes); 1372 if (resource == null) 1373 throw new IllegalArgumentException ("xaRes not enlisted " + xaRes); 1374 1375 switch (status) 1376 { 1377 case Status.STATUS_ACTIVE: 1378 case Status.STATUS_MARKED_ROLLBACK: 1379 break; 1380 case Status.STATUS_PREPARING: 1381 throw new IllegalStateException ("Already started preparing, tx=" + 1382 toString()); 1383 case Status.STATUS_ROLLING_BACK: 1384 throw new IllegalStateException ("Already started rolling back, tx=" 1385 + toString()); 1386 case Status.STATUS_PREPARED: 1387 throw new IllegalStateException ("Already prepared, tx=" + 1388 toString()); 1389 case Status.STATUS_COMMITTING: 1390 throw new IllegalStateException ("Already started committing, tx=" + 1391 toString()); 1392 case Status.STATUS_COMMITTED: 1393 throw new IllegalStateException ("Already committed, tx=" + 1394 toString()); 1395 case Status.STATUS_ROLLEDBACK: 1396 throw new IllegalStateException ("Already rolled back, tx=" + 1397 toString()); 1398 case Status.STATUS_NO_TRANSACTION: 1399 throw new IllegalStateException ("No transaction, tx=" + toString()); 1400 case Status.STATUS_UNKNOWN: 1401 throw new IllegalStateException ("Unknown state, tx=" + toString()); 1402 default: 1403 throw new IllegalStateException ("Illegal status: " + 1404 TxUtils.getStatusAsString(status) + 1405 ", tx=" + toString()); 1406 } 1407 1408 try 1409 { 1410 return resource.delistResource(xaRes, flag); 1411 } 1412 catch (XAException xae) 1413 { 1414 logXAException(xae); 1415 status = Status.STATUS_MARKED_ROLLBACK; 1416 cause = xae; 1417 return false; 1418 } 1419 } 1420 finally 1421 { 1422 unlock(); 1423 } 1424 } 1425 1426 public boolean enlistResource(XAResource xaRes) 1427 throws RollbackException , 1428 java.lang.IllegalStateException , 1429 SystemException 1430 { 1431 if (xaRes == null) 1432 throw new IllegalArgumentException ("null xaRes, tx=" + toString()); 1433 1434 lock(); 1435 try 1436 { 1437 if (trace) 1438 log.trace("enlistResource(): Entered, tx=" + toString() + 1439 ", status=" + TxUtils.getStatusAsString(status) + 1440 ", xaRes=" + xaRes); 1441 1442 checkStatus(); 1443 1444 if (resourcesEnded) 1445 throw new IllegalStateException ("Too late to enlist resources, tx=" 1446 + toString()); 1447 1448 try 1450 { 1451 EnlistedXAResource resource = findResource(xaRes); 1452 1453 if (resource != null) 1455 { 1456 if (resource.isEnlisted()) 1457 { 1458 if (trace) 1459 log.trace("Already enlisted: tx=" + toString() + 1460 ", status=" + TxUtils.getStatusAsString(status) + 1461 ", xaRes=" + xaRes); 1462 return true; } 1464 if (resource.isDelisted(xaRes)) 1465 resource = null; 1469 else 1470 return resource.startResource(); 1471 } 1472 1473 if (parentCoordinator != null && recoveryCoordinator == null) 1475 registerResourceWithParentCoordinator(); 1476 1477 resource = findResourceManager(xaRes); 1478 if (resource != null) 1479 { 1480 resource = addResource(xaRes, resource.getXid(), resource); 1484 return resource.startResource(); 1485 } 1486 1487 resource = addResource(xaRes, createXidBranch(), null); 1489 return resource.startResource(); 1490 } 1491 catch (XAException xae) 1492 { 1493 logXAException(xae); 1494 cause = xae; 1495 return false; 1496 } 1497 } 1498 finally 1499 { 1500 unlock(); 1501 } 1502 1503 } 1504 1505 public int getStatus() 1506 { 1507 if (done) 1508 return Status.STATUS_NO_TRANSACTION; 1509 return status; 1510 } 1511 1512 public void registerSynchronization(Synchronization s) 1513 throws RollbackException , 1514 java.lang.IllegalStateException , 1515 SystemException 1516 { 1517 if (s == null) 1518 throw new IllegalArgumentException ("Null synchronization, tx=" + 1519 toString()); 1520 1521 lock(); 1522 try 1523 { 1524 if (trace) 1525 { 1526 log.trace("registerSynchronization(): Entered, " + 1527 "tx=" + toString() + 1528 ", status=" + TxUtils.getStatusAsString(status)); 1529 } 1530 1531 checkStatus(); 1532 1533 if (syncCount == syncAllocSize) 1534 { 1535 syncAllocSize = 2 * syncAllocSize; 1537 1538 Synchronization [] sy = new Synchronization [syncAllocSize]; 1539 System.arraycopy(sync, 0, sy, 0, syncCount); 1540 sync = sy; 1541 } 1542 sync[syncCount++] = s; 1543 1544 if (parentCoordinator != null && recoveryCoordinator == null) 1546 registerResourceWithParentCoordinator(); 1547 } 1548 finally 1549 { 1550 unlock(); 1551 } 1552 } 1553 1554 public void setRollbackOnly() 1555 throws java.lang.IllegalStateException , 1556 SystemException 1557 { 1558 lock(); 1559 try 1560 { 1561 if (trace) 1562 log.trace("setRollbackOnly(): Entered, tx=" + toString() + 1563 ", status=" + TxUtils.getStatusAsString(status)); 1564 1565 switch (status) 1566 { 1567 case Status.STATUS_ACTIVE: 1568 if (parentCoordinator != null && recoveryCoordinator == null) 1570 { 1571 try 1572 { 1573 registerResourceWithParentCoordinator(); 1574 } 1575 catch (RollbackException e) 1576 { 1577 log.warn("RollbackException in setRollbackOnly: " + e); 1578 } 1579 } 1580 case Status.STATUS_PREPARING: 1582 case Status.STATUS_PREPARED: 1583 status = Status.STATUS_MARKED_ROLLBACK; 1584 case Status.STATUS_MARKED_ROLLBACK: 1586 case Status.STATUS_ROLLING_BACK: 1587 return; 1588 case Status.STATUS_COMMITTING: 1589 throw new IllegalStateException ("Already started committing, tx=" + 1590 toString()); 1591 case Status.STATUS_COMMITTED: 1592 throw new IllegalStateException ("Already committed, tx=" + 1593 toString()); 1594 case Status.STATUS_ROLLEDBACK: 1595 throw new IllegalStateException ("Already rolled back, tx=" + 1596 toString()); 1597 case Status.STATUS_NO_TRANSACTION: 1598 throw new IllegalStateException ("No transaction, tx=" + toString()); 1599 case Status.STATUS_UNKNOWN: 1600 throw new IllegalStateException ("Unknown state, tx=" + toString()); 1601 default: 1602 throw new IllegalStateException ("Illegal status: " + 1603 TxUtils.getStatusAsString(status) + 1604 ", tx=" + toString()); 1605 } 1606 } 1607 finally 1608 { 1609 unlock(); 1610 } 1611 } 1612 1613 1615 1626 public void enlistRemoteResource(Resource remoteRes) 1627 throws RollbackException , 1628 java.lang.IllegalStateException 1629 { 1630 if (remoteRes == null) 1631 throw new IllegalArgumentException ("null remoteRes, tx=" + toString()); 1632 1633 lock(); 1634 try 1635 { 1636 if (trace) 1637 log.trace("enlistRemoteResource(): Entered, tx=" + toString() + 1638 ", status=" + TxUtils.getStatusAsString(status)); 1639 1640 checkStatus(); 1641 1642 if (resourcesEnded) 1643 throw new IllegalStateException ("Too late to enlist resources, tx=" 1644 + toString()); 1645 1646 if (parentCoordinator != null && recoveryCoordinator == null) 1648 registerResourceWithParentCoordinator(); 1649 1650 EnlistedRemoteResource resource = 1652 new EnlistedRemoteResource(remoteRes); 1653 remoteResources.add(resource); 1654 } 1655 finally 1656 { 1657 unlock(); 1658 } 1659 } 1660 1661 1670 public int prepare(Xid inboundXid) 1671 throws HeuristicHazardException, 1672 HeuristicMixedException , 1673 HeuristicRollbackException , 1674 RollbackException 1675 { 1676 lock(); 1677 try 1678 { 1679 if (trace) 1680 log.trace("Preparing, tx=" + toString() + 1681 ", status=" + TxUtils.getStatusAsString(status)); 1682 1683 checkWork(); 1684 1685 beforePrepare(); 1686 1687 if (status == Status.STATUS_ACTIVE) 1688 { 1689 switch (getCommitStrategy()) 1690 { 1691 case 0: 1692 if (trace) 1694 log.trace("Prepare foreign tx=" + toString() + 1695 ": No resources."); 1696 if (syncCount == 0) 1697 { 1698 status = Status.STATUS_COMMITTED; 1700 completeTransaction(); 1701 return XAResource.XA_RDONLY; 1702 } 1703 else 1704 { status = Status.STATUS_PREPARED; 1707 return XAResource.XA_OK; 1708 } 1709 default: 1710 if (trace) 1712 log.trace("Prepare foreign tx=" + toString() + 1713 ": one or more resources."); 1714 if (!prepareResources()) 1715 { 1716 boolean commitDecision = 1717 status == Status.STATUS_PREPARED && 1718 (heuristicCode == HEUR_NONE || 1719 heuristicCode == XAException.XA_HEURCOM); 1720 1721 if (commitDecision) 1722 { 1723 try 1726 { 1727 RecoveryLogger logger = 1728 TxManager.getInstance().getRecoveryLogger(); 1729 if (logger != null) 1730 { 1731 if (inboundXid == null) 1732 { 1733 completionHandler = logger.savePrepareDecision( 1734 xid.getLocalIdValue(), 1735 xid.getFormatId(), 1736 xid.getGlobalTransactionId(), 1737 recoveryCoordinatorToString(recoveryCoordinator), 1738 getStringfiedRemoteResourcesThatVotedCommit()); 1739 } 1740 else 1741 { 1742 completionHandler = logger.savePrepareDecision( 1743 xid.getLocalIdValue(), 1744 inboundXid, 1745 getStringfiedRemoteResourcesThatVotedCommit()); 1746 } 1747 } 1748 } 1749 catch (Throwable e) 1750 { 1751 if (e instanceof RecoveryTestingException) 1752 throw (RecoveryTestingException) e; 1753 log.warn("FAILED WHEN WRITING PREPARE RECORD." 1754 + " Rolling back now."); 1755 } 1756 } 1757 } 1758 else 1759 { 1760 if (syncCount == 0) 1761 { 1762 if (trace) 1764 log.trace("Prepared foreign tx=" + toString() + 1765 ": All readonly," + 1766 " no Synchronizations registered"); 1767 status = Status.STATUS_COMMITTED; 1768 completeTransaction(); 1769 return XAResource.XA_RDONLY; 1770 } 1771 else 1772 { if (trace) 1775 log.trace("Prepared foreign tx=" + toString() + 1776 ": All readonly, but there is at least" + 1777 " one Synchronization registered"); 1778 status = Status.STATUS_PREPARED; 1779 return XAResource.XA_OK; 1780 } 1781 } 1782 break; 1783 } 1784 } 1785 1786 if (status != Status.STATUS_PREPARED) 1787 { 1788 Throwable causedByThrowable = cause; 1791 rollbackResourcesAndCompleteTransaction(); 1792 1793 throw new JBossRollbackException("Unable to prepare, tx=" + 1795 toString() + ", status=" + 1796 TxUtils.getStatusAsString(status), 1797 causedByThrowable); 1798 } 1799 1800 if (inboundXid == null) 1801 createPreparedTimeout(); 1802 1803 return XAResource.XA_OK; 1805 } 1806 finally 1807 { 1808 unlock(); 1809 } 1810 } 1811 1812 1817 public void commit(boolean onePhase) 1818 throws RollbackException , 1819 HeuristicHazardException, 1820 HeuristicMixedException , 1821 HeuristicRollbackException , 1822 SystemException 1823 { 1824 checkWork(); 1825 1826 if (onePhase) 1828 { 1829 commit(); 1830 return; 1831 } 1832 1833 lock(); 1835 try 1836 { 1837 if (trace) 1838 log.trace("Committing two phase, tx=" + toString() + 1839 ", status=" + TxUtils.getStatusAsString(status)); 1840 1841 cancelPreparedTimeout(); 1842 1843 switch (status) 1844 { 1845 case Status.STATUS_PREPARING: 1846 throw new IllegalStateException ("Still preparing, tx=" + 1847 toString()); 1848 case Status.STATUS_ROLLING_BACK: 1849 throw new IllegalStateException ("Already started rolling back, tx=" 1850 + toString()); 1851 case Status.STATUS_ROLLEDBACK: 1852 instanceDone(); 1853 throw new IllegalStateException ("Already rolled back, tx=" + 1855 toString()); 1856 case Status.STATUS_COMMITTING: 1857 if (trace) 1858 log.trace("Already committing, tx=" + toString()); 1859 return; 1860 case Status.STATUS_COMMITTED: 1861 instanceDone(); 1862 if (trace) 1864 log.trace("Already committed, tx=" + toString()); 1865 return; 1866 case Status.STATUS_NO_TRANSACTION: 1867 throw new IllegalStateException ("No transaction, tx=" + toString()); 1868 case Status.STATUS_UNKNOWN: 1869 throw new IllegalStateException ("Unknown state, tx=" + toString()); 1870 case Status.STATUS_MARKED_ROLLBACK: 1871 endResources(); 1872 rollbackResourcesAndCompleteTransaction(); 1873 checkHeuristics(); 1874 throw new RollbackException ("Already marked for rollback, tx=" + 1875 toString()); 1876 case Status.STATUS_PREPARED: 1877 break; 1878 default: 1879 throw new IllegalStateException ("Illegal status: " + 1880 TxUtils.getStatusAsString(status) + 1881 ", tx=" + toString()); 1882 } 1883 1884 commitResources(false); 1885 1886 if (status == Status.STATUS_COMMITTING) 1887 { 1888 if (xaResourcesToRetry > 0) 1890 commitXAResourcesAfterTimeout(); 1891 checkHeuristics(); 1892 } 1893 else if (status != Status.STATUS_COMMITTED) 1894 { 1895 Throwable causedByThrowable = cause; 1896 1897 throw new JBossRollbackException("Unable to commit, tx=" + 1899 toString() + ", status=" + 1900 TxUtils.getStatusAsString(status), 1901 causedByThrowable); 1902 } 1903 else 1904 { 1905 cancelTimeout(); 1906 doAfterCompletion(); 1907 checkHeuristics(); 1908 instanceDone(); 1909 1910 if (trace) 1911 log.trace("Committed OK, tx=" + toString()); 1912 } 1913 } 1914 finally 1915 { 1916 unlock(); 1917 } 1918 } 1919 1920 1923 public void rollbackBranch() 1924 throws HeuristicCommitException , 1925 HeuristicMixedException , 1926 HeuristicHazardException, 1927 java.lang.IllegalStateException 1928 { 1929 lock(); 1930 try 1931 { 1932 1933 if (trace) 1934 log.trace("rollbackBranch(): Entered, tx=" + toString() + 1935 ", status=" + TxUtils.getStatusAsString(status)); 1936 1937 checkWork(); 1938 cancelPreparedTimeout(); 1939 1940 switch (status) 1941 { 1942 case Status.STATUS_ACTIVE: 1943 case Status.STATUS_PREPARED: 1944 status = Status.STATUS_MARKED_ROLLBACK; 1945 case Status.STATUS_MARKED_ROLLBACK: 1947 endResources(); 1948 rollbackResourcesAndCompleteTransaction(); 1949 switch (getFullHeuristicCode()) 1950 { 1951 case XAException.XA_HEURHAZ: 1952 if (trace) 1953 log.trace("Throwing HeuristicHazardException, tx=" + 1954 toString() + ", status=" + 1955 TxUtils.getStatusAsString(status)); 1956 throw new HeuristicHazardException(); 1957 case XAException.XA_HEURMIX: 1958 if (trace) 1959 log.trace("Throwing HeuristicMixedException, tx=" + 1960 toString() + ", status=" + 1961 TxUtils.getStatusAsString(status)); 1962 throw new HeuristicMixedException (); 1963 case XAException.XA_HEURRB: 1964 if (trace) 1965 log.trace("Not throwing HeuristicRollbackException, tx=" + 1966 toString() + ", status=" + 1967 TxUtils.getStatusAsString(status)); 1968 break; 1969 case XAException.XA_HEURCOM: 1970 if (trace) 1971 log.trace("Throwing HeuristicCommitException, tx=" + 1972 toString() + ", status=" + 1973 TxUtils.getStatusAsString(status)); 1974 throw new HeuristicCommitException (); 1975 } 1976 return; 1977 case Status.STATUS_PREPARING: 1978 status = Status.STATUS_MARKED_ROLLBACK; 1980 return; case Status.STATUS_ROLLEDBACK: 1982 if (trace) 1983 log.trace("Already rolledback, tx=" + toString()); 1984 return; 1985 default: 1986 throw new IllegalStateException ("Cannot rollback(), tx=" + 1987 toString() + ", status=" + 1988 TxUtils.getStatusAsString(status)); 1989 } 1990 } 1991 finally 1992 { 1993 Thread.interrupted(); unlock(); 1995 } 1996 } 1997 1998 2002 public void forget() 2003 { 2004 lock(); 2005 try { 2006 if (heuristicCode == HEUR_NONE && !heuristicHazard) 2007 return; 2008 2009 if (status != Status.STATUS_COMMITTED && 2010 status != Status.STATUS_ROLLEDBACK && 2011 (status != Status.STATUS_COMMITTING || !heuristicHazard) && 2012 (status != Status.STATUS_ROLLING_BACK || !heuristicHazard)) 2013 return; 2014 2015 if (forgetResources()) 2016 { 2017 RecoveryLogger logger = TxManager.getInstance().getRecoveryLogger(); 2019 if (logger != null) 2020 { 2021 logger.clearHeuristicStatus(xid.getLocalIdValue()); 2022 if (status == Status.STATUS_COMMITTED && 2023 completionHandler != null) 2024 completionHandler.handleTxCompletion(xid.getLocalIdValue()); 2025 } 2026 instanceDone(); 2027 } 2028 } 2029 finally 2030 { 2031 unlock(); 2032 } 2033 } 2034 2035 2043 public int replayCompletion(final Resource r) 2044 { 2045 lock(); 2046 try 2047 { 2048 if (status != Status.STATUS_MARKED_ROLLBACK && 2049 status != Status.STATUS_ROLLING_BACK && 2050 status != Status.STATUS_ROLLEDBACK) 2051 { 2052 final boolean pendingCommits = 2053 (status == Status.STATUS_COMMITTING && 2054 remoteResourcesToRetry > 0); 2055 2056 Runnable runnable = new Runnable () 2057 { 2058 public void run() 2059 { 2060 try 2061 { 2062 if (trace) 2063 log.trace("Replay completion thread: " + 2064 " committing remote resource " + r); 2065 r.commit(); 2066 2067 if (trace) 2068 log.trace("Replay completion thread: " + 2069 " committed remote resource " + r); 2070 } 2071 catch (Throwable ignored) 2072 { 2073 if (trace) 2074 log.trace("Replay completion thread: ignored exception" 2075 + " when committing remote resource " + r , 2076 ignored); 2077 } 2078 2079 if (pendingCommits) 2080 { 2081 lock(); 2082 try 2083 { 2084 if (trace) 2085 log.trace("Replay completion thread: calling " + 2086 "retryCommitRemoteResources"); 2087 2088 retryCommitRemoteResources(); 2089 if (xaResourcesToRetry == 0 && 2090 remoteResourcesToRetry == 0 && 2091 heuristicCode == HEUR_NONE) 2092 completeTransaction(); 2093 } 2094 finally 2095 { 2096 unlock(); 2097 } 2098 } 2099 if (trace) 2100 log.trace("Replay completion thread: exiting"); 2101 } 2102 }; 2103 Thread t = new Thread (runnable, "replayCompletionThread"); 2104 2105 t.start(); 2106 } 2107 return status; 2108 } 2109 finally 2110 { 2111 unlock(); 2112 } 2113 } 2114 2115 2125 public long getTimeLeftBeforeTimeout(boolean errorRollback) 2126 throws RollbackException 2127 { 2128 if (errorRollback && status != Status.STATUS_ACTIVE) 2129 throw new RollbackException ("Transaction is not active: " + 2130 TxUtils.getStatusAsString(status)); 2131 return (start + timeoutPeriod) - System.currentTimeMillis(); 2132 } 2133 2134 public int getAssociatedThreadCount() 2135 { 2136 lock(); 2137 try 2138 { 2139 return threads.size(); 2140 } 2141 finally 2142 { 2143 unlock(); 2144 } 2145 } 2146 2147 public Set getAssociatedThreads() 2148 { 2149 lock(); 2150 try 2151 { 2152 return Collections.unmodifiableSet(threads); 2153 } 2154 finally 2155 { 2156 unlock(); 2157 } 2158 } 2159 2160 public int hashCode() 2161 { 2162 return xid.hashCode(); 2163 } 2164 2165 public String toString() 2166 { 2167 return "TransactionImpl:" + xidFactory.toString(xid); 2168 } 2169 2170 public boolean equals(Object obj) 2171 { 2172 if (obj != null && obj instanceof TransactionImpl) 2173 return getLocalIdValue() == (((TransactionImpl) obj).getLocalIdValue()); 2174 return false; 2175 } 2176 2177 2178 2183 public long getLocalIdValue() 2184 { 2185 return xid.getLocalIdValue(); 2186 } 2187 2188 2193 public LocalId getLocalId() 2194 { 2195 return xid.getLocalId(); 2196 } 2197 2198 2202 public GlobalId getGlobalId() 2203 { 2204 return xid.getTrulyGlobalId(); 2205 } 2206 2207 2210 public XidImpl getXid() 2211 { 2212 return xid; 2213 } 2214 2215 2218 public TxPropagationContext getPropagationContext() 2219 { 2220 if (dtmPropagationContext == null) 2221 { 2222 Coordinator coordinatorToPropagate; 2223 2224 if (parentCoordinator == null || interpositionEnabled || 2225 !Proxy.isProxyClass(parentCoordinator.getClass())) 2226 { 2227 coordinatorToPropagate = 2231 dtmCoordinatorFactory.createCoordinator(getLocalIdValue()); 2232 } 2233 else 2234 { 2235 coordinatorToPropagate = parentCoordinator; 2238 } 2239 2240 dtmPropagationContext = 2242 new TxPropagationContext(xid.getFormatId(), 2243 xid.getGlobalTransactionId(), 2244 0, 2245 coordinatorToPropagate, 2246 null ); 2247 } 2248 2249 try 2251 { 2252 dtmPropagationContext.timeout = 2253 TMUtil.divideAndRoundUp(getTimeLeftBeforeTimeout(true), 1000); 2254 } 2255 catch (RollbackException transactionNotActive) 2256 { 2257 if (status == Status.STATUS_MARKED_ROLLBACK) 2258 dtmPropagationContext.timeout = 0; 2259 else 2260 dtmPropagationContext = null; 2261 } 2262 return dtmPropagationContext; 2263 } 2264 2265 2268 public Object getOTSPropagationContext() 2269 { 2270 if (otsPropagationContext == null) 2271 { 2272 if (parentCoordinator == null || interpositionEnabled || 2273 Proxy.isProxyClass(parentCoordinator.getClass())) 2274 { 2275 otsPropagationContext = 2279 otsContextFactory.createOTSContext(xid.getFormatId(), 2280 xid.getGlobalTransactionId(), 2281 getLocalIdValue()); 2282 } 2283 else 2284 { 2285 otsPropagationContext = 2288 otsContextFactory.createOTSContext(xid.getFormatId(), 2289 xid.getGlobalTransactionId(), 2290 parentCoordinator); 2291 } 2292 } 2293 2294 try 2296 { 2297 otsContextFactory.setTimeout( 2298 otsPropagationContext, 2299 TMUtil.divideAndRoundUp(getTimeLeftBeforeTimeout(true), 1000)); 2300 } 2301 catch (RollbackException transactionNotActive) 2302 { 2303 if (status == Status.STATUS_MARKED_ROLLBACK) 2304 otsContextFactory.setTimeout(otsPropagationContext, 0); 2305 else 2306 otsPropagationContext = null; 2307 } 2308 return otsPropagationContext; 2309 } 2310 2311 public void setHeuristicStatus(LogRecord.HeurData heurData) 2312 { 2313 lock(); 2314 try 2315 { 2316 if (status != heurData.transactionStatus) 2317 { 2318 if (status == Status.STATUS_PREPARED) 2319 cancelPreparedTimeout(); 2320 2321 status = heurData.transactionStatus; 2322 2323 if (status == Status.STATUS_COMMITTING) 2324 { 2325 retryCommitRemoteResources(); 2326 2327 if (xaResourcesToRetry > 0) 2328 { 2329 commitXAResourcesAfterTimeout(); 2332 } 2333 else if (remoteResourcesToRetry == 0 && heuristicCode == HEUR_NONE) 2334 { 2335 completeTransaction(); 2337 } 2338 else 2339 { 2340 } 2343 } 2344 else if (status == Status.STATUS_ROLLING_BACK) 2345 { 2346 rollbackResourcesAndCompleteTransaction(); 2347 } 2348 } 2349 } 2350 finally 2351 { 2352 unlock(); 2353 } 2354 } 2355 2356 2358 2367 boolean isPreparedOrHeuristicallyCompletedJCAInboundTx() 2368 { 2369 return inboundBranchQualifier != null 2370 && (status == Status.STATUS_PREPARED 2371 || (getFullHeuristicCode() != HEUR_NONE 2372 && (status == Status.STATUS_COMMITTED 2373 || status == Status.STATUS_ROLLEDBACK))); 2374 } 2375 2376 2382 Xid getInboundXid() 2383 { 2384 return new Xid () 2385 { 2386 public int getFormatId() 2387 { 2388 return xid.getFormatId(); 2389 } 2390 2391 public byte[] getGlobalTransactionId() 2392 { 2393 return xid.getGlobalTransactionId(); 2394 } 2395 2396 public byte[] getBranchQualifier() 2397 { 2398 return (byte[])inboundBranchQualifier.clone(); 2399 } 2400 }; 2401 } 2402 2403 void associateCurrentThread() 2404 { 2405 Thread.interrupted(); 2406 lock(); 2407 try 2408 { 2409 threads.add(Thread.currentThread()); 2410 } 2411 finally 2412 { 2413 unlock(); 2414 } 2415 } 2416 2417 void disassociateCurrentThread() 2418 { 2419 if (done) 2421 { 2422 threads.remove(Thread.currentThread()); 2423 } 2424 else 2425 { 2426 lock(); 2428 try 2429 { 2430 threads.remove(Thread.currentThread()); 2431 } 2432 finally 2433 { 2434 unlock(); 2435 } 2436 } 2437 Thread.interrupted(); 2438 } 2439 2440 2443 synchronized void lock() 2444 { 2445 if (done) 2446 throw new IllegalStateException ("Transaction has terminated, tx=" + 2447 toString()); 2448 2449 Thread currentThread = Thread.currentThread(); 2450 if (locked != null && locked != currentThread) 2451 { 2452 log.debug("Lock contention, tx=" + toString() + 2453 " otherThread=" + locked); 2454 2456 while (locked != null && locked != currentThread) 2457 { 2458 try 2459 { 2460 wait(); 2464 } 2465 catch (InterruptedException ex) 2466 { 2467 } 2469 2470 if (done) 2471 throw new IllegalStateException ( 2472 "Transaction has now terminated, tx=" + toString()); 2473 } 2474 } 2475 2476 locked = currentThread; 2477 ++lockDepth; 2478 } 2479 2480 2483 synchronized void unlock() 2484 { 2485 Thread currentThread = Thread.currentThread(); 2486 if (locked == null || locked != currentThread) 2487 { 2488 log.warn("Unlocking, but not locked, tx=" + toString() + 2489 " otherThread=" + locked, 2490 new Throwable ("[Stack trace]")); 2491 } 2492 else 2493 { 2494 if (--lockDepth == 0) 2495 { 2496 locked = null; 2497 notify(); 2498 } 2499 } 2500 } 2501 2502 2505 synchronized void deactivate() 2506 { 2507 lock(); 2508 try 2509 { 2510 cancelTimeout(); 2511 cancelPreparedTimeout(); 2512 cancelXARetryTimeout(); 2513 2514 parentCoordinator = null; 2518 sync = null; 2519 xaResources = null; 2520 remoteResources = null; 2521 transactionLocalMap.clear(); 2522 threads.clear(); 2523 2524 status = Status.STATUS_NO_TRANSACTION; 2526 2527 notifyAll(); 2529 2530 done = true; 2532 } 2533 finally 2534 { 2535 unlock(); 2536 } 2537 } 2538 2539 2544 Work getWork() 2545 { 2546 return work; 2547 } 2548 2549 2558 void setWork(Work work) 2559 throws WorkCompletedException 2560 { 2561 lock(); 2562 try 2563 { 2564 if (work == null) 2565 { 2566 this.work = null; 2567 return; 2568 } 2569 2570 if (status == Status.STATUS_NO_TRANSACTION || status == Status.STATUS_UNKNOWN) 2571 throw new WorkCompletedException ("The transaction is not active " + 2572 toString() + ": " + 2573 TxUtils.getStatusAsString(status), 2574 WorkException.TX_RECREATE_FAILED); 2575 else if (status != Status.STATUS_ACTIVE) 2576 throw new WorkCompletedException ("Too late to start work " + 2577 toString() + ": " + 2578 TxUtils.getStatusAsString(status), 2579 WorkException.TX_CONCURRENT_WORK_DISALLOWED); 2580 else if (this.work != null) 2581 throw new WorkCompletedException ("Already have work " + toString() + 2582 ": " + this.work, 2583 WorkException.TX_CONCURRENT_WORK_DISALLOWED); 2584 2585 this.work = work; 2586 } 2587 finally 2588 { 2589 unlock(); 2590 } 2591 } 2592 2593 2596 boolean isDone() 2597 { 2598 return done || (heuristicCode != HEUR_NONE && 2599 (status == Status.STATUS_COMMITTING || 2600 status == Status.STATUS_COMMITTED || 2601 status == Status.STATUS_ROLLING_BACK || 2602 status == Status.STATUS_ROLLEDBACK)); 2603 } 2604 2605 Object getTransactionLocalValue(TransactionLocal tlocal) 2606 { 2607 return transactionLocalMap.get(tlocal); 2608 } 2609 2610 void putTransactionLocalValue(TransactionLocal tlocal, Object value) 2611 { 2612 transactionLocalMap.put(tlocal, value); 2613 } 2614 2615 boolean containsTransactionLocal(TransactionLocal tlocal) 2616 { 2617 return transactionLocalMap.containsKey(tlocal); 2618 } 2619 2620 2622 2625 private void beforePrepare() 2626 throws HeuristicMixedException , 2627 HeuristicRollbackException , 2628 RollbackException 2629 { 2630 checkIntegrity(); 2631 2632 doBeforeCompletion(); 2633 2634 if (trace) 2635 log.trace("Before completion done, tx=" + toString() + 2636 ", status=" + TxUtils.getStatusAsString(status)); 2637 2638 endResources(); 2639 } 2640 2641 2644 private void checkIntegrity() 2645 throws HeuristicMixedException , 2646 HeuristicRollbackException , 2647 RollbackException 2648 { 2649 checkBeforeStatus(); 2651 2652 TransactionIntegrity integrity = TxManager.getInstance().getTransactionIntegrity(); 2653 if (integrity != null) 2654 { 2655 unlock(); 2657 try 2658 { 2659 integrity.checkTransactionIntegrity(this); 2660 } 2661 finally 2662 { 2663 lock(); 2664 } 2665 2666 checkBeforeStatus(); 2668 } 2669 } 2670 2671 2674 private void checkBeforeStatus() 2675 throws HeuristicMixedException , 2676 HeuristicRollbackException , 2677 RollbackException 2678 { 2679 switch (status) 2680 { 2681 case Status.STATUS_PREPARING: 2682 throw new IllegalStateException ("Already started preparing, tx=" + 2683 toString()); 2684 case Status.STATUS_PREPARED: 2685 throw new IllegalStateException ("Already prepared, tx=" + toString()); 2686 case Status.STATUS_ROLLING_BACK: 2687 throw new IllegalStateException ("Already started rolling back, tx=" + 2688 toString()); 2689 case Status.STATUS_ROLLEDBACK: 2690 instanceDone(); 2691 throw new IllegalStateException ("Already rolled back, tx=" + 2693 toString()); 2694 case Status.STATUS_COMMITTING: 2695 throw new IllegalStateException ("Already started committing, tx=" + 2696 toString()); 2697 case Status.STATUS_COMMITTED: 2698 instanceDone(); 2699 throw new IllegalStateException ("Already committed, tx=" + toString()); 2701 case Status.STATUS_NO_TRANSACTION: 2702 throw new IllegalStateException ("No transaction, tx=" + toString()); 2703 case Status.STATUS_UNKNOWN: 2704 throw new IllegalStateException ("Unknown state, tx=" + toString()); 2705 case Status.STATUS_MARKED_ROLLBACK: 2706 endResources(); 2707 rollbackResourcesAndCompleteTransaction(); 2708 checkHeuristicsButDoNotThrowHeuristicHazard(); 2709 throw new RollbackException ("Already marked for rollback, tx=" + 2710 toString()); 2711 case Status.STATUS_ACTIVE: 2712 break; 2713 default: 2714 throw new IllegalStateException ("Illegal status: " + 2715 TxUtils.getStatusAsString(status) + 2716 ", tx=" + toString()); 2717 } 2718 } 2719 2720 2723 private void completeTransaction() 2724 { 2725 cancelTimeout(); 2726 doAfterCompletion(); 2727 instanceDone(); 2728 } 2729 2730 2737 private void checkStatus() 2738 throws RollbackException 2739 { 2740 switch (status) 2741 { 2742 case Status.STATUS_ACTIVE: 2743 case Status.STATUS_PREPARING: 2744 break; 2745 case Status.STATUS_PREPARED: 2746 throw new IllegalStateException ("Already prepared, tx=" + toString()); 2747 case Status.STATUS_COMMITTING: 2748 throw new IllegalStateException ("Already started committing, tx=" + 2749 toString()); 2750 case Status.STATUS_COMMITTED: 2751 throw new IllegalStateException ("Already committed, tx=" + toString()); 2752 case Status.STATUS_MARKED_ROLLBACK: 2753 throw new RollbackException ("Already marked for rollback, tx=" + 2754 toString()); 2755 case Status.STATUS_ROLLING_BACK: 2756 throw new RollbackException ("Already started rolling back, tx=" + 2757 toString()); 2758 case Status.STATUS_ROLLEDBACK: 2759 throw new RollbackException ("Already rolled back, tx=" + toString()); 2760 case Status.STATUS_NO_TRANSACTION: 2761 throw new IllegalStateException ("No transaction, tx=" + toString()); 2762 case Status.STATUS_UNKNOWN: 2763 throw new IllegalStateException ("Unknown state, tx=" + toString()); 2764 default: 2765 throw new IllegalStateException ("Illegal status: " + 2766 TxUtils.getStatusAsString(status) + 2767 ", tx=" + toString()); 2768 } 2769 } 2770 2771 2775 private void interruptThreads() 2776 { 2777 TxManager manager = TxManager.getInstance(); 2778 if (manager.isInterruptThreads()) 2779 { 2780 HashSet clone = (HashSet ) threads.clone(); 2781 threads.clear(); 2782 for (Iterator i = clone.iterator(); i.hasNext();) 2783 { 2784 Thread thread = (Thread ) i.next(); 2785 try 2786 { 2787 thread.interrupt(); 2788 } 2789 catch (Throwable ignored) 2790 { 2791 if (trace) 2792 log.trace("Ignored error interrupting thread: " + 2793 thread, ignored); 2794 } 2795 } 2796 } 2797 } 2798 2799 private void logXAException(XAException xae) 2800 { 2801 log.warn("XAException: tx=" + toString() + " errorCode=" + 2802 TxUtils.getXAErrorCodeAsString(xae.errorCode), xae); 2803 if (xaExceptionFormatter != null) 2804 xaExceptionFormatter.formatXAException(xae, log); 2805 } 2806 2807 2810 private synchronized void instanceDone() 2811 { 2812 TxManager manager = TxManager.getInstance(); 2813 2814 if (status == Status.STATUS_COMMITTED) 2815 manager.incCommitCount(); 2816 else 2817 manager.incRollbackCount(); 2818 2819 parentCoordinator = null; 2823 sync = null; 2824 xaResources = null; 2825 remoteResources = null; 2826 transactionLocalMap.clear(); 2827 threads.clear(); 2828 2829 manager.releaseTransactionImpl(this); 2831 2832 status = Status.STATUS_NO_TRANSACTION; 2834 2835 notifyAll(); 2837 2838 done = true; 2840 } 2841 2842 2846 private void cancelTimeout() 2847 { 2848 if (timeout != null) 2849 { 2850 unlock(); 2851 try 2852 { 2853 timeout.cancel(); 2854 } 2855 catch (Exception e) 2856 { 2857 if (trace) 2858 log.trace("failed to cancel timeout, tx=" + toString(), e); 2859 } 2860 finally 2861 { 2862 lock(); 2863 } 2864 timeout = null; 2865 } 2866 } 2867 2868 2871 private void createPreparedTimeout() 2872 { 2873 preparedTimeout = timeoutFactory.createTimeout( 2874 System.currentTimeMillis() + 2875 TxManager.getInstance().getPreparedTimeoutMillis(), 2876 new TimeoutTarget() 2877 { 2878 public void timedOut(Timeout timeout) 2879 { 2880 if (trace) 2881 log.trace("Prepared timeout expired for tx=" + 2882 TransactionImpl.this.toString() + 2883 ", calling replayCompletion " + 2884 "on the recovery coordinator"); 2885 try 2886 { 2887 recoveryCoordinator.replayCompletion(registeredResource); 2888 } 2889 catch (NoSuchObjectException noCoordinator) 2890 { 2891 if (trace) 2892 { 2893 log.trace("Exception in replayCompletion: " + 2894 "no coordinator for tx=" + toString(), 2895 noCoordinator); 2896 log.trace("Rolling back transaction branch, tx=" + 2897 TransactionImpl.this.toString()); 2898 } 2899 try 2900 { 2901 rollbackBranch(); 2902 } 2903 catch (Exception e) 2904 { 2905 if (trace) 2906 log.trace("Exception in transaction branch rollback," 2907 + " tx=" + TransactionImpl.this.toString(), 2908 e); 2909 2910 } 2911 } 2912 catch (Exception ignore) 2913 { 2914 if (trace) 2915 log.trace("Ignoring exception in replayCompletion, tx=" 2916 + TransactionImpl.this.toString(), ignore); 2917 } 2918 if (!done) 2919 { 2920 lock(); 2921 try 2922 { 2923 if (preparedTimeout != null) 2924 { 2925 preparedTimeout = timeoutFactory.createTimeout( 2926 System.currentTimeMillis() + 2927 TxManager.getInstance() 2928 .getPreparedTimeoutMillis(), 2929 this); 2930 } 2931 } 2932 finally 2933 { 2934 unlock(); 2935 } 2936 } 2937 } 2938 }); 2939 } 2940 2941 2944 private void cancelPreparedTimeout() 2945 { 2946 if (preparedTimeout != null) 2947 { 2948 Timeout pt = preparedTimeout; 2949 preparedTimeout = null; 2950 2951 unlock(); 2952 try 2953 { 2954 pt.cancel(); 2955 } 2956 catch (Exception e) 2957 { 2958 if (trace) 2959 log.trace("failed to cancel prepared timeout, tx=" + toString(), 2960 e); 2961 } 2962 finally 2963 { 2964 lock(); 2965 } 2966 } 2967 } 2968 2969 2972 private EnlistedXAResource findResource(XAResource xaRes) 2973 { 2974 for (int idx = xaResources.size() - 1; idx >= 0; --idx) 2983 { 2984 EnlistedXAResource resource = 2985 (EnlistedXAResource) xaResources.get(idx); 2986 if (xaRes == resource.getXAResource()) 2987 return resource; 2988 } 2989 2990 return null; 2991 } 2992 2993 private EnlistedXAResource findResourceManager(XAResource xaRes) 2994 throws XAException 2995 { 2996 for (int i = 0; i < xaResources.size(); ++i) 2997 { 2998 EnlistedXAResource resource = (EnlistedXAResource) xaResources.get(i); 2999 if (resource.isResourceManager(xaRes)) 3000 return resource; 3001 } 3002 return null; 3003 } 3004 3005 3018 private EnlistedXAResource addResource(XAResource xaRes, 3019 Xid branchXid, 3020 EnlistedXAResource sameRMResource) 3021 { 3022 EnlistedXAResource resource = 3023 new EnlistedXAResource(xaRes, branchXid, sameRMResource); 3024 xaResources.add(resource); 3025 3026 if (lastResource == null && xaRes instanceof LastResource) 3028 lastResource = resource; 3029 3030 return resource; 3031 } 3032 3033 3036 private void endResources() 3037 { 3038 for (int idx = 0; idx < xaResources.size(); ++idx) 3039 { 3040 EnlistedXAResource resource = 3041 (EnlistedXAResource) xaResources.get(idx); 3042 try 3043 { 3044 resource.endResource(); 3045 } 3046 catch (XAException xae) 3047 { 3048 logXAException(xae); 3049 status = Status.STATUS_MARKED_ROLLBACK; 3050 cause = xae; 3051 } 3052 } 3053 resourcesEnded = true; } 3055 3056 3057 3061 private void doBeforeCompletion() 3062 { 3063 unlock(); 3064 try 3065 { 3066 for (int i = 0; i < syncCount; i++) 3067 { 3068 try 3069 { 3070 if (trace) 3071 log.trace("calling sync " + i + ", " + sync[i] + 3072 " tx=" + toString()); 3073 3074 sync[i].beforeCompletion(); 3075 } 3076 catch (Throwable t) 3077 { 3078 if (trace) 3079 log.trace("failed before completion " + sync[i], t); 3080 3081 status = Status.STATUS_MARKED_ROLLBACK; 3082 3083 cause = t; 3085 break; 3086 } 3087 } 3088 } 3089 finally 3090 { 3091 lock(); 3092 } 3093 } 3094 3095 3099 private void doAfterCompletion() 3100 { 3101 unlock(); 3103 try 3104 { 3105 for (int i = 0; i < syncCount; i++) 3106 { 3107 try 3108 { 3109 sync[i].afterCompletion(status); 3110 } 3111 catch (Throwable t) 3112 { 3113 if (trace) 3114 log.trace("failed after completion " + sync[i], t); 3115 } 3116 } 3117 } 3118 finally 3119 { 3120 lock(); 3121 } 3122 } 3123 3124 3132 private static int groupHeuristics(int code1, int code2) 3133 { 3134 switch (code2) 3135 { 3136 case XAException.XA_HEURMIX: 3137 code1 = XAException.XA_HEURMIX; 3138 break; 3139 case XAException.XA_HEURRB: 3140 if (code1 == HEUR_NONE) 3141 code1 = XAException.XA_HEURRB; 3142 else if (code1 == XAException.XA_HEURCOM || 3143 code1 == XAException.XA_HEURHAZ) 3144 code1 = XAException.XA_HEURMIX; 3145 break; 3146 case XAException.XA_HEURCOM: 3147 if (code1 == HEUR_NONE) 3148 code1 = XAException.XA_HEURCOM; 3149 else if (code1 == XAException.XA_HEURRB || 3150 code1 == XAException.XA_HEURHAZ) 3151 code1 = XAException.XA_HEURMIX; 3152 break; 3153 case XAException.XA_HEURHAZ: 3154 if (code1 == HEUR_NONE) 3155 code1 = XAException.XA_HEURHAZ; 3156 else if (code1 == XAException.XA_HEURCOM || 3157 code1 == XAException.XA_HEURRB) 3158 code1 = XAException.XA_HEURMIX; 3159 break; 3160 default: 3161 throw new IllegalArgumentException (); 3162 } 3163 3164 return code1; 3165 } 3166 3167 3182 private void gotHeuristic(EnlistedResource resource, int code) 3183 { 3184 heuristicCode = groupHeuristics(heuristicCode, code); 3185 if (resource != null) 3186 resource.remember(code); 3187 } 3188 3189 3195 private int consolidateHeuristics() 3196 { 3197 if (committedResources > 0 && rolledbackResources > 0) 3198 heuristicCode = XAException.XA_HEURMIX; 3199 3200 return heuristicCode; 3201 } 3202 3203 3211 private int getFullHeuristicCode() 3212 { 3213 return (heuristicHazard) ? 3214 groupHeuristics(heuristicCode, XAException.XA_HEURHAZ) : 3215 heuristicCode; 3216 } 3217 3218 3221 private void checkHeuristics() 3222 throws HeuristicHazardException, 3223 HeuristicMixedException , 3224 HeuristicRollbackException 3225 { 3226 if (committedResources > 0 && rolledbackResources > 0) 3227 heuristicCode = XAException.XA_HEURMIX; 3228 3229 switch (getFullHeuristicCode()) 3230 { 3231 case XAException.XA_HEURHAZ: 3232 if (trace) 3233 log.trace("Throwing HeuristicHazardException, tx=" + toString() + 3234 ", status=" + TxUtils.getStatusAsString(status)); 3235 throw new HeuristicHazardException(); 3236 case XAException.XA_HEURMIX: 3237 if (trace) 3238 log.trace("Throwing HeuristicMixedException, tx=" + toString() + 3239 ", status=" + TxUtils.getStatusAsString(status)); 3240 throw new HeuristicMixedException (); 3241 case XAException.XA_HEURRB: 3242 if (trace) 3243 log.trace("Throwing HeuristicRollbackException, tx=" + toString() + 3244 ", status=" + TxUtils.getStatusAsString(status)); 3245 throw new HeuristicRollbackException (); 3246 case XAException.XA_HEURCOM: 3247 if (trace) 3250 log.trace("NOT Throwing HeuristicCommitException, tx=" + toString() 3251 + ", status=" + TxUtils.getStatusAsString(status)); 3252 return; 3253 } 3254 } 3255 3256 private void checkHeuristicsButDoNotThrowHeuristicHazard() 3257 throws HeuristicMixedException , 3258 HeuristicRollbackException 3259 { 3260 if (committedResources > 0 && rolledbackResources > 0) 3261 heuristicCode = XAException.XA_HEURMIX; 3262 3263 switch (getFullHeuristicCode()) 3264 { 3265 case XAException.XA_HEURHAZ: 3266 if (TxManager.getInstance().isReportHeuristicHazardAsHeuristicMixed()) 3267 { 3268 if (trace) 3269 log.trace("Throwing HeuristicMixedException instead of " + 3270 "HeuristicHazardException, tx=" + toString() + 3271 ", status=" + TxUtils.getStatusAsString(status)); 3272 throw new HeuristicMixedException (); 3273 } 3274 else 3275 { 3276 if (trace) 3277 log.trace("NOT throwing HeuristicHazardException, tx=" + 3278 toString() + ", status=" + 3279 TxUtils.getStatusAsString(status)); 3280 return; 3281 } 3282 case XAException.XA_HEURMIX: 3283 if (trace) 3284 log.trace("Throwing HeuristicMixedException, tx=" + toString() + 3285 ", status=" + TxUtils.getStatusAsString(status)); 3286 throw new HeuristicMixedException (); 3287 case XAException.XA_HEURRB: 3288 if (trace) 3289 log.trace("Throwing HeuristicRollbackException, tx=" + toString() + 3290 ", status=" + TxUtils.getStatusAsString(status)); 3291 throw new HeuristicRollbackException (); 3292 case XAException.XA_HEURCOM: 3293 if (trace) 3296 log.trace("NOT Throwing HeuristicCommitException, tx=" + toString() 3297 + ", status=" + TxUtils.getStatusAsString(status)); 3298 return; 3299 } 3300 } 3301 3302 3311 private void registerResourceWithParentCoordinator() 3312 throws RollbackException 3313 { 3314 if (trace) 3315 log.trace("registerResourceWithParentCoordinator(): Entered, tx=" + 3316 toString() + ", status=" + TxUtils.getStatusAsString(status)); 3317 3318 Resource r = null; 3319 3320 if (Proxy.isProxyClass(parentCoordinator.getClass())) 3321 { 3322 if (dtmResourceFactory != null) 3324 r = dtmResourceFactory.createResource(getLocalIdValue()); 3325 else 3326 { 3327 log.warn("Missing DTM resource factory, tx=" + toString()); 3328 status = Status.STATUS_MARKED_ROLLBACK; 3329 throw new RollbackException ("Missing DTM resource factory"); 3330 } 3331 } 3332 else 3333 { 3334 if (otsResourceFactory != null) 3336 r = otsResourceFactory.createResource(getLocalIdValue()); 3337 else 3338 { 3339 log.warn("Missing OTS resource factory, tx=" + toString()); 3340 status = Status.STATUS_MARKED_ROLLBACK; 3341 throw new RollbackException ("Missing OTS resource factory"); 3342 } 3343 } 3344 3345 try 3346 { 3347 unlock(); 3348 try 3349 { 3350 recoveryCoordinator = parentCoordinator.registerResource(r); 3351 registeredResource = r; 3352 } 3353 finally 3354 { 3355 lock(); 3356 } 3357 } 3358 catch (TransactionInactiveException e) 3359 { 3360 status = Status.STATUS_MARKED_ROLLBACK; 3361 if (trace) 3362 log.trace("Got TransactionInactiveException, " + 3363 "throwing RollbackException"); 3364 throw new RollbackException (e.toString()); 3365 } 3366 catch (TransactionRolledbackException e) 3367 { 3368 status = Status.STATUS_MARKED_ROLLBACK; 3369 if (trace) 3370 log.trace("Got TransactionRolledbackException, " + 3371 "throwing RollbackException"); 3372 throw new RollbackException (e.toString()); 3373 } 3374 catch (RemoteException e) 3375 { 3376 status = Status.STATUS_MARKED_ROLLBACK; 3377 if (trace) 3378 log.trace("Got RemoteException, throwing RollbackException"); 3379 throw new RollbackException (e.toString()); 3380 } 3381 } 3382 3383 3394 private boolean prepareResources() 3395 { 3396 boolean readOnly = true; 3397 3398 status = Status.STATUS_PREPARING; 3399 3400 3402 if (trace) 3403 log.trace("Preparing " + xaResources.size() + " XA resource(s)"); 3404 3405 for (int i = 0; i < xaResources.size(); ++i) 3406 { 3407 if (status != Status.STATUS_PREPARING) 3409 return false; 3410 3411 EnlistedXAResource resource = (EnlistedXAResource) xaResources.get(i); 3412 3413 if (resource.isResourceManager() == false) 3414 continue; 3416 if (resource == lastResource) 3418 continue; 3419 3420 try 3421 { 3422 int vote = resource.prepare(); 3423 3424 if (trace) 3425 { 3426 String strVote = 3427 (vote == RS_VOTE_OK) ? 3428 "OK" : 3429 ((vote == RS_VOTE_READONLY) ? "READONLY" : "ROLLBACK"); 3430 3431 log.trace("XA resource voted " + strVote); 3432 } 3433 3434 if (vote == RS_VOTE_OK) 3435 readOnly = false; 3436 else if (vote != RS_VOTE_READONLY) 3437 { 3438 if (trace) 3440 log.trace("prepareResources got a rollback vote " + 3441 "from an XA resource, tx=" + toString() + 3442 " resource=" + resource, new Exception ()); 3443 status = Status.STATUS_MARKED_ROLLBACK; 3444 return false; 3445 } 3446 } 3447 catch (XAException e) 3448 { 3449 readOnly = false; 3450 logXAException(e); 3451 switch (e.errorCode) 3452 { 3453 case XAException.XA_HEURCOM: 3454 gotHeuristic(resource, e.errorCode); 3457 break; 3458 case XAException.XA_HEURRB: 3459 case XAException.XA_HEURMIX: 3460 case XAException.XA_HEURHAZ: 3461 gotHeuristic(resource, e.errorCode); 3463 default: 3465 cause = e; 3466 status = Status.STATUS_MARKED_ROLLBACK; 3467 break; 3468 } 3469 } 3470 catch (Throwable t) 3471 { 3472 if (t instanceof RecoveryTestingException) 3473 throw (RecoveryTestingException)t; 3474 3475 if (trace) 3476 log.trace("unhandled throwable in prepareResources " + 3477 toString(), t); 3478 status = Status.STATUS_MARKED_ROLLBACK; 3479 cause = t; 3480 return false; 3481 } 3482 } 3483 3484 3486 if (trace) 3487 log.trace("Preparing " + remoteResources.size() + 3488 " remote resource(s)"); 3489 3490 for (int i = 0; i < remoteResources.size(); ++i) 3491 { 3492 if (status != Status.STATUS_PREPARING) 3494 return false; 3495 3496 EnlistedRemoteResource resource = 3497 (EnlistedRemoteResource) remoteResources.get(i); 3498 3499 try 3500 { 3501 int vote = resource.prepare(); 3502 3503 if (trace) 3504 { 3505 String strVote = 3506 (vote == RS_VOTE_OK) ? 3507 "OK" : 3508 ((vote == RS_VOTE_READONLY) ? "READONLY" : "ROLLBACK"); 3509 3510 log.trace("Remote resource voted " + strVote); 3511 } 3512 3513 if (vote == RS_VOTE_OK) 3514 readOnly = false; 3515 else if (vote != RS_VOTE_READONLY) 3516 { 3517 if (trace) 3519 log.trace("prepareResources got a rollback vote " + 3520 "from a remote resource, tx=" + toString() + 3521 ", resource=" + resource, new Exception ()); 3522 status = Status.STATUS_MARKED_ROLLBACK; 3523 return false; 3524 } 3525 } 3526 catch (Exception e) 3527 { 3528 if (trace) 3534 log.trace("Exception in prepareResources, tx=" + toString(), e); 3535 3536 if (e instanceof HeuristicMixedException ) 3537 gotHeuristic(resource, XAException.XA_HEURMIX); 3538 else if (e instanceof HeuristicHazardException) 3539 gotHeuristic(resource, XAException.XA_HEURHAZ); 3540 3541 cause = e; 3542 status = Status.STATUS_MARKED_ROLLBACK; 3543 } 3544 } 3545 3546 if (status != Status.STATUS_PREPARING) 3548 return false; 3549 3550 if (lastResource != null) 3552 { 3553 try 3554 { 3555 lastResource.prepareLastResource(); 3556 lastResource.commit(false); 3557 } 3558 catch (XAException e) 3559 { 3560 if (trace) 3561 log.trace("prepareResources got XAException" + 3562 " when committing last resource, tx=" + toString(), e); 3563 logXAException(e); 3564 switch (e.errorCode) 3565 { 3566 case XAException.XA_HEURRB: 3569 case XAException.XA_HEURMIX: 3570 case XAException.XA_HEURHAZ: 3571 gotHeuristic(lastResource, e.errorCode); 3573 default: 3575 status = Status.STATUS_MARKED_ROLLBACK; 3577 cause = e; 3578 return false; } 3581 } 3582 catch (Throwable t) 3583 { 3584 if (trace) 3585 log.trace("unhandled throwable in prepareResources, tx=" + 3586 toString(), t); 3587 status = Status.STATUS_MARKED_ROLLBACK; 3588 cause = t; 3589 return false; } 3592 } 3593 3594 if (status == Status.STATUS_PREPARING) 3595 status = Status.STATUS_PREPARED; 3596 else 3597 return false; 3598 3599 return readOnly; 3600 } 3601 3602 3606 private void commitResources(boolean onePhase) 3607 { 3608 status = Status.STATUS_COMMITTING; 3609 doCommitResources(onePhase); 3610 if (xaResourcesToRetry > 0 || remoteResourcesToRetry > 0) 3611 { 3612 int retryLimit = TxManager.getInstance().getCompletionRetryLimit(); 3613 for (int n = 0; 3614 n < retryLimit && 3615 (xaResourcesToRetry > 0 || remoteResourcesToRetry > 0); 3616 n++) 3617 { 3618 sleep(TxManager.getInstance().getCompletionRetryTimeoutMillis()); 3619 doCommitResources(onePhase); 3620 } 3621 } 3622 checkCommitCompletion(); 3623 } 3624 3625 3628 private void doCommitResources(boolean onePhase) 3629 { 3630 xaResourcesToRetry = 0; 3631 remoteResourcesToRetry = 0; 3632 3633 for (int i = 0; i < xaResources.size(); ++i) 3635 { 3636 3637 if (status != Status.STATUS_COMMITTING) 3639 return; 3640 3641 EnlistedXAResource resource = 3642 (EnlistedXAResource) xaResources.get(i); 3643 3644 if (onePhase == false && lastResource == resource) 3646 continue; 3647 3648 try 3649 { 3650 resource.commit(onePhase); 3651 } 3652 catch (XAException e) 3653 { 3654 logXAException(e); 3655 switch (e.errorCode) 3656 { 3657 case XAException.XA_HEURRB: 3660 case XAException.XA_HEURMIX: 3661 case XAException.XA_HEURHAZ: 3662 gotHeuristic(resource, e.errorCode); 3664 if (onePhase) 3665 status = Status.STATUS_MARKED_ROLLBACK; 3666 break; 3667 case XAException.XAER_RMERR: 3668 gotHeuristic(null, XAException.XA_HEURRB); 3672 if (onePhase) 3673 status = Status.STATUS_MARKED_ROLLBACK; 3674 break; 3675 case XAException.XAER_RMFAIL: 3676 case XAException.XA_RETRY: 3677 if (onePhase) 3678 status = Status.STATUS_MARKED_ROLLBACK; 3679 else 3680 xaResourcesToRetry++; 3682 break; 3683 case XAException.XAER_NOTA: 3684 case XAException.XAER_INVAL: 3685 case XAException.XAER_PROTO: 3686 default: 3687 cause = e; 3689 if (onePhase) 3690 status = Status.STATUS_MARKED_ROLLBACK; 3691 else 3692 log.warn("Could not recover from unexpected XAException: " + 3693 "tx=" + toString() + " errorCode=" + 3694 TxUtils.getXAErrorCodeAsString(e.errorCode), e); 3695 break; 3696 } 3697 } 3698 catch (Throwable t) 3699 { 3700 if (t instanceof RecoveryTestingException) 3701 throw (RecoveryTestingException) t; 3702 if (trace) 3703 log.trace("Unhandled throwable in doCommitResources " + 3704 toString(), t); 3705 } 3706 } 3707 3708 for (int i = 0; i < remoteResources.size(); ++i) 3710 { 3711 if (status != Status.STATUS_COMMITTING) 3713 return; 3714 3715 EnlistedRemoteResource resource = 3716 (EnlistedRemoteResource) remoteResources.get(i); 3717 3718 try 3719 { 3720 resource.commit(onePhase); 3721 } 3722 catch (TransactionRolledbackException e) 3723 { 3724 if (trace) 3725 log.trace("Exception in doCommitResources, tx=" + toString(), e); 3726 3727 if (onePhase) 3728 status = Status.STATUS_MARKED_ROLLBACK; 3729 else 3730 { 3731 gotHeuristic(null, XAException.XA_HEURRB); 3734 } 3735 } 3736 catch (HeuristicRollbackException e) 3737 { 3738 if (trace) 3739 log.trace("Exception in doCommitResources, tx=" + toString(), e); 3740 3741 gotHeuristic(resource, XAException.XA_HEURRB); 3742 if (onePhase) 3743 status = Status.STATUS_MARKED_ROLLBACK; 3744 } 3745 catch (HeuristicMixedException e) 3746 { 3747 if (trace) 3748 log.trace("Exception in doCommitResources, tx=" + toString(), e); 3749 3750 gotHeuristic(resource, XAException.XA_HEURMIX); 3751 if (onePhase) 3752 status = Status.STATUS_MARKED_ROLLBACK; 3753 } 3754 catch (HeuristicHazardException e) 3755 { 3756 if (trace) 3757 log.trace("Exception in doCommitResources, tx=" + toString(), e); 3758 3759 gotHeuristic(resource, XAException.XA_HEURHAZ); 3760 if (onePhase) 3761 status = Status.STATUS_MARKED_ROLLBACK; 3762 } 3763 catch (TransactionNotPreparedException e) 3764 { 3765 cause = e; 3767 if (trace) 3768 log.trace("Exception in doCommitResources, tx=" + toString(), e); 3769 if (onePhase) 3770 status = Status.STATUS_MARKED_ROLLBACK; 3771 else 3772 log.warn("Could not recover from unexpected exception in " + 3773 "doCommitResources: tx=" + toString() + 3774 " exception=" + e); 3775 } 3776 catch (NoSuchObjectException e) 3777 { 3778 if (trace) 3779 log.trace("Exception in doCommitResources, tx=" + toString(), e); 3780 if (onePhase) 3781 status = Status.STATUS_MARKED_ROLLBACK; 3782 else 3783 { 3784 log.warn("Ignoring NoSuchObjectException in doCommitResources: " 3787 + " tx=" + toString() + " exception=" + e); 3788 } 3789 } 3790 catch (RemoteException e) 3791 { 3792 if (trace) 3793 log.trace("Exception in doCommitResources, tx=" + toString(), e); 3794 if (onePhase) 3795 status = Status.STATUS_MARKED_ROLLBACK; 3796 else 3797 { 3798 remoteResourcesToRetry++; 3800 } 3801 } 3802 } 3803 } 3804 3805 3808 private void commitXAResourcesAfterTimeout() 3809 { 3810 xaRetryTimeout = timeoutFactory.createTimeout( 3811 System.currentTimeMillis() + 3812 TxManager.getInstance().getXARetryTimeoutMillis(), 3813 new TimeoutTarget() 3814 { 3815 public void timedOut(Timeout timeout) 3816 { 3817 if (trace) 3818 log.trace("XA retry timeout expired for tx=" + 3819 TransactionImpl.this.toString() + 3820 ", retrying commit on XAResources"); 3821 lock(); 3822 try 3823 { 3824 retryCommitXAResources(); 3825 if (xaResourcesToRetry > 0) 3826 { 3827 xaRetryTimeout = timeoutFactory.createTimeout( 3828 System.currentTimeMillis() + 3829 TxManager.getInstance().getXARetryTimeoutMillis(), 3830 this); 3831 } 3832 else if (remoteResourcesToRetry == 0 && 3833 heuristicCode == HEUR_NONE) 3834 { 3835 completeTransaction(); 3836 } 3837 } 3838 finally 3839 { 3840 unlock(); 3841 } 3842 } 3843 }); 3844 } 3845 3846 private void retryCommitXAResources() 3849 { 3850 if (trace) 3851 log.trace("Retrying commit XA resources, tx=" + toString() + 3852 ", status=" + TxUtils.getStatusAsString(status) + 3853 ", xaResourcesToRetry=" + xaResourcesToRetry); 3854 3855 xaResourcesToRetry = 0; 3856 3857 for (int i = 0; i < xaResources.size(); ++i) 3858 { 3859 EnlistedXAResource resource = 3860 (EnlistedXAResource) xaResources.get(i); 3861 3862 if (lastResource == resource) 3864 continue; 3865 3866 try 3867 { 3868 resource.commit(false); 3869 } 3870 catch (XAException e) 3871 { 3872 logXAException(e); 3873 switch (e.errorCode) 3874 { 3875 case XAException.XA_HEURRB: 3878 case XAException.XA_HEURMIX: 3879 case XAException.XA_HEURHAZ: 3880 gotHeuristic(resource, e.errorCode); 3882 break; 3883 case XAException.XAER_RMERR: 3884 gotHeuristic(null, XAException.XA_HEURRB); 3888 break; 3889 case XAException.XAER_RMFAIL: 3890 case XAException.XA_RETRY: 3891 xaResourcesToRetry++; 3893 break; 3894 case XAException.XAER_NOTA: 3895 case XAException.XAER_INVAL: 3896 case XAException.XAER_PROTO: 3897 default: 3898 log.warn("Could not recover from unexpected XAException: " + 3900 "tx=" + toString() + " errorCode=" + 3901 TxUtils.getXAErrorCodeAsString(e.errorCode), e); 3902 break; 3903 } 3904 } 3905 catch (Throwable t) 3906 { 3907 if (t instanceof RecoveryTestingException) 3908 throw (RecoveryTestingException) t; 3909 if (trace) 3910 log.trace("unhandled throwable in retryCommitXAResources " + 3911 this, t); 3912 } 3913 } 3914 3915 if (trace) 3916 log.trace("Finished retrying commit XA resources, tx=" + toString() + 3917 ", status=" + TxUtils.getStatusAsString(status) + 3918 ", xaResourcesToRetry=" + xaResourcesToRetry); 3919 3920 checkCommitCompletion(); 3921 } 3922 3923 private void retryCommitRemoteResources() 3926 { 3927 if (trace) 3928 log.trace("Retrying commit remote resources, tx=" + toString() + 3929 ", status=" + TxUtils.getStatusAsString(status) + 3930 ", " + remoteResources.size() + " remote resources"); 3931 3932 remoteResourcesToRetry = 0; 3933 3934 for (int i = 0; i < remoteResources.size(); ++i) 3936 { 3937 EnlistedRemoteResource resource = 3938 (EnlistedRemoteResource) remoteResources.get(i); 3939 3940 try 3941 { 3942 resource.commit(false); 3943 } 3944 catch (HeuristicRollbackException e) 3945 { 3946 if (trace) 3947 log.trace("Exception in retryCommitRemoteResources, tx=" + 3948 toString(), e); 3949 3950 gotHeuristic(resource, XAException.XA_HEURRB); 3951 } 3952 catch (HeuristicMixedException e) 3953 { 3954 if (trace) 3955 log.trace("Exception in retryCommitRemoteResources, tx=" + 3956 toString(), e); 3957 3958 gotHeuristic(resource, XAException.XA_HEURMIX); 3959 } 3960 catch (HeuristicHazardException e) 3961 { 3962 if (trace) 3963 log.trace("Exception in retryCommitRemoteResources, tx=" + 3964 toString(), e); 3965 3966 gotHeuristic(resource, XAException.XA_HEURHAZ); 3967 } 3968 catch (TransactionNotPreparedException e) 3969 { 3970 cause = e; 3972 if (trace) 3973 log.trace("Exception in retryCommitRemoteResources, tx=" + 3974 toString(), e); 3975 log.warn("Could not recover from unexpected exception in " + 3976 "retryCommitRemoteResources: tx=" + toString() + 3977 " exception=" + e); 3978 } 3979 catch (NoSuchObjectException e) 3980 { 3981 if (trace) 3982 log.trace("Exception in retryCommitRemoteResources, tx=" + 3983 toString(), e); 3984 3985 log.warn("Ignoring NoSuchObjectException in " + 3988 "retryCommitRemoteResources: tx=" + toString() + 3989 " exception=" + e); 3990 } 3991 catch (RemoteException e) 3992 { 3993 if (trace) 3994 log.trace("Exception in retryCommitRemoteResources, tx=" + 3995 toString(), e); 3996 3997 remoteResourcesToRetry++; 3999 } 4000 } 4001 4002 if (trace) 4003 log.trace("Finished retrying commit remote resources, tx=" + toString() 4004 + ", status=" + TxUtils.getStatusAsString(status) + 4005 ", remoteResourcesToRetry=" + remoteResourcesToRetry + 4006 " of " + remoteResources.size() + " remote resources"); 4007 4008 checkCommitCompletion(); 4009 } 4010 4011 private void checkCommitCompletion() 4012 { 4013 if (status != Status.STATUS_COMMITTING) 4014 return; 4015 4016 consolidateHeuristics(); 4017 4018 if (xaResourcesToRetry == 0 && remoteResourcesToRetry == 0) 4019 { 4020 status = Status.STATUS_COMMITTED; 4021 if (heuristicHazard || heuristicCode != HEUR_NONE) 4022 { 4023 heuristicHazard = false; 4024 4025 RecoveryLogger logger = TxManager.getInstance().getRecoveryLogger(); 4029 if (logger != null) 4030 logger.saveHeuristicStatus(xid.getLocalIdValue(), 4031 foreignTx, 4032 xid.getFormatId(), 4033 xid.getGlobalTransactionId(), 4034 inboundBranchQualifier, 4035 status, 4036 heuristicCode, 4037 heuristicHazard, 4038 getXAResourceHeuristics(), 4039 getRemoteResourceHeuristics()); 4040 if (!foreignTx && 4041 !TxManager.getInstance().isRootBranchRemembersHeuristicDecisions() && 4042 forgetResources()) 4043 { 4044 if (logger != null) 4046 { 4047 long localId = xid.getLocalIdValue(); 4048 logger.clearHeuristicStatus(localId); 4049 if (completionHandler != null) 4050 completionHandler.handleTxCompletion(localId); 4051 } 4052 } 4053 } 4054 else if (completionHandler != null) 4055 completionHandler.handleTxCompletion(xid.getLocalIdValue()); 4056 } 4057 else if (!heuristicHazard) 4058 { 4059 heuristicHazard = true; 4060 4061 RecoveryLogger logger = TxManager.getInstance().getRecoveryLogger(); 4064 if (logger != null) 4065 logger.saveHeuristicStatus(xid.getLocalIdValue(), 4066 foreignTx, 4067 xid.getFormatId(), 4068 xid.getGlobalTransactionId(), 4069 inboundBranchQualifier, 4070 status, 4071 heuristicCode, 4072 heuristicHazard, 4073 getXAResourceHeuristics(), 4074 getRemoteResourceHeuristics()); 4075 4076 if (!foreignTx && 4077 !TxManager.getInstance().isRootBranchRemembersHeuristicDecisions()) 4078 forgetResources(); 4079 } 4080 } 4081 4082 4086 private void rollbackResourcesAndCompleteTransaction() 4087 { 4088 status = Status.STATUS_ROLLING_BACK; 4089 doRollbackResources(); 4090 if (xaResourcesToRetry > 0 || remoteResourcesToRetry > 0) 4091 { 4092 int retryLimit = TxManager.getInstance().getCompletionRetryLimit(); 4093 for (int n = 0; 4094 n < retryLimit && 4095 (xaResourcesToRetry > 0 || remoteResourcesToRetry > 0); 4096 n++) 4097 { 4098 sleep(TxManager.getInstance().getCompletionRetryTimeoutMillis()); 4099 doRollbackResources(); 4100 } 4101 } 4102 4103 if (xaResourcesToRetry == 0 && remoteResourcesToRetry == 0) 4104 { 4105 status = Status.STATUS_ROLLEDBACK; 4106 4107 if (consolidateHeuristics() != HEUR_NONE || heuristicHazard) 4108 { 4109 heuristicHazard = false; 4110 4111 RecoveryLogger logger = TxManager.getInstance().getRecoveryLogger(); 4115 if (logger != null) 4116 logger.saveHeuristicStatus(xid.getLocalIdValue(), 4117 foreignTx, 4118 xid.getFormatId(), 4119 xid.getGlobalTransactionId(), 4120 inboundBranchQualifier, 4121 status, 4122 heuristicCode, 4123 heuristicHazard, 4124 getXAResourceHeuristics(), 4125 getRemoteResourceHeuristics()); 4126 if (!foreignTx && 4127 !TxManager.getInstance().isRootBranchRemembersHeuristicDecisions() && 4128 forgetResources()) 4129 { 4130 if (logger != null) 4132 { 4133 long localId = xid.getLocalIdValue(); 4134 logger.clearHeuristicStatus(localId); 4135 } 4136 } 4137 } 4138 else 4139 completeTransaction(); 4140 } 4141 else 4142 { 4143 if (!heuristicHazard) 4144 { 4145 heuristicHazard = true; 4146 consolidateHeuristics(); 4147 4148 RecoveryLogger logger = TxManager.getInstance().getRecoveryLogger(); 4151 if (logger != null) 4152 logger.saveHeuristicStatus(xid.getLocalIdValue(), 4153 foreignTx, 4154 xid.getFormatId(), 4155 xid.getGlobalTransactionId(), 4156 inboundBranchQualifier, 4157 status, 4158 heuristicCode, 4159 heuristicHazard, 4160 getXAResourceHeuristics(), 4161 getRemoteResourceHeuristics()); 4162 } 4163 if (xaResourcesToRetry > 0) 4164 rollbackXAResourcesAfterTimeout(); 4165 } 4166 } 4167 4168 4171 private void doRollbackResources() 4172 { 4173 xaResourcesToRetry = 0; 4174 remoteResourcesToRetry = 0; 4175 4176 for (int i = 0; i < xaResources.size(); ++i) 4178 { 4179 EnlistedXAResource resource = (EnlistedXAResource) xaResources.get(i); 4180 try 4181 { 4182 resource.rollback(); 4183 } 4184 catch (XAException e) 4185 { 4186 logXAException(e); 4187 switch (e.errorCode) 4188 { 4189 case XAException.XA_HEURCOM: 4192 case XAException.XA_HEURMIX: 4193 case XAException.XA_HEURHAZ: 4194 gotHeuristic(resource, e.errorCode); 4195 continue; 4196 default: 4197 cause = e; 4198 break; 4199 } 4200 } 4201 catch (Throwable t) 4202 { 4203 if (t instanceof RecoveryTestingException) 4204 throw (RecoveryTestingException) t; 4205 if (trace) 4206 log.trace("unhandled throwable in doRollbackResources " + this, 4207 t); 4208 } 4209 if (resource.getState() == RS_VOTE_OK) 4210 xaResourcesToRetry++; 4211 } 4212 4213 for (int i = 0; i < remoteResources.size(); ++i) 4215 { 4216 EnlistedRemoteResource resource = 4217 (EnlistedRemoteResource) remoteResources.get(i); 4218 4219 try 4220 { 4221 resource.rollback(); 4222 } 4223 catch (HeuristicCommitException e) 4224 { 4225 gotHeuristic(resource, XAException.XA_HEURCOM); 4226 continue; 4227 } 4228 catch (HeuristicMixedException e) 4229 { 4230 gotHeuristic(resource, XAException.XA_HEURMIX); 4231 continue; 4232 } 4233 catch (HeuristicHazardException e) 4234 { 4235 gotHeuristic(resource, XAException.XA_HEURHAZ); 4236 continue; 4237 } 4238 catch (RemoteException e) 4239 { 4240 remoteResourcesToRetry++; 4245 if (trace) 4246 log.trace("Ignoring exception in remote resource rollback, tx=" + 4247 toString(), e); 4248 } 4249 } 4250 } 4251 4252 4255 private void rollbackXAResourcesAfterTimeout() 4256 { 4257 xaRetryTimeout = timeoutFactory.createTimeout( 4258 System.currentTimeMillis() + 4259 TxManager.getInstance().getXARetryTimeoutMillis(), 4260 new TimeoutTarget() 4261 { 4262 public void timedOut(Timeout timeout) 4263 { 4264 if (trace) 4265 log.trace("XA retry timeout expired for tx=" + 4266 TransactionImpl.this.toString() + 4267 ", retrying rollback on XAResources"); 4268 lock(); 4269 try 4270 { 4271 retryRollbackXAResources(); 4272 if (xaResourcesToRetry > 0) 4273 { 4274 xaRetryTimeout = timeoutFactory.createTimeout( 4275 System.currentTimeMillis() + 4276 TxManager.getInstance().getXARetryTimeoutMillis(), 4277 this); 4278 } 4279 else if (remoteResourcesToRetry == 0 && 4280 heuristicCode == HEUR_NONE) 4281 { 4282 completeTransaction(); 4283 } 4284 } 4285 finally 4286 { 4287 unlock(); 4288 } 4289 } 4290 }); 4291 } 4292 4293 4296 private void cancelXARetryTimeout() 4297 { 4298 if (xaRetryTimeout != null) 4299 { 4300 Timeout rt = xaRetryTimeout; 4301 xaRetryTimeout = null; 4302 4303 unlock(); 4304 try 4305 { 4306 rt.cancel(); 4307 } 4308 catch (Exception e) 4309 { 4310 if (trace) 4311 log.trace("failed to cancel XA retry timeout, tx=" + toString(), 4312 e); 4313 } 4314 finally 4315 { 4316 lock(); 4317 } 4318 } 4319 } 4320 4321 private int[] getXAResourceHeuristics() 4322 { 4323 if (xaResourcesWithHeuristicDecisions == null) 4324 return null; 4325 else 4326 { 4327 int[] heurCodes = new int[xaResourcesWithHeuristicDecisions.size()]; 4328 for (int i = 0; i < xaResourcesWithHeuristicDecisions.size(); ++i) 4329 { 4330 EnlistedResource resource = 4331 (EnlistedResource) xaResourcesWithHeuristicDecisions.get(i); 4332 heurCodes[i] = resource.getHeuristicCode(); 4333 } 4334 return heurCodes; 4335 } 4336 } 4337 4338 private HeuristicStatus[] getRemoteResourceHeuristics() 4339 { 4340 if (remoteResourcesWithHeuristicDecisions == null) 4341 return null; 4342 else 4343 { 4344 HeuristicStatus s[] = 4345 new HeuristicStatus[remoteResourcesWithHeuristicDecisions.size()]; 4346 for (int i = 0; i < remoteResourcesWithHeuristicDecisions.size(); ++i) 4347 { 4348 EnlistedRemoteResource resource = 4349 (EnlistedRemoteResource) remoteResourcesWithHeuristicDecisions.get(i); 4350 s[i] = new HeuristicStatus( 4351 resource.getHeuristicCode(), 4352 resourceToString(resource.getRemoteResource())); 4353 } 4354 return s; 4355 } 4356 } 4357 4358 4359 private void retryRollbackXAResources() 4360 { 4361 xaResourcesToRetry = 0; 4362 4363 for (int i = 0; i < xaResources.size(); ++i) 4365 { 4366 EnlistedXAResource resource = (EnlistedXAResource) xaResources.get(i); 4367 try 4368 { 4369 resource.rollback(); 4370 } 4371 catch (XAException e) 4372 { 4373 logXAException(e); 4374 switch (e.errorCode) 4375 { 4376 case XAException.XA_HEURCOM: 4379 case XAException.XA_HEURMIX: 4380 case XAException.XA_HEURHAZ: 4381 gotHeuristic(resource, e.errorCode); 4382 continue; 4383 default: 4384 cause = e; 4385 break; 4386 } 4387 } 4388 catch (Throwable t) 4389 { 4390 if (t instanceof RecoveryTestingException) 4391 throw (RecoveryTestingException) t; 4392 if (trace) 4393 log.trace("unhandled throwable in retryRollbackXAResources " + 4394 this, t); 4395 } 4396 if (resource.getState() == RS_VOTE_OK) 4397 xaResourcesToRetry++; 4398 } 4399 4400 if (xaResourcesToRetry == 0 && remoteResourcesToRetry == 0) 4401 status = Status.STATUS_ROLLEDBACK; 4402 } 4403 4404 private boolean forgetResources() 4405 { 4406 boolean success = true; 4407 if (xaResourcesWithHeuristicDecisions != null) 4408 { 4409 for (int i = 0; i < xaResourcesWithHeuristicDecisions.size(); ++i) 4410 { 4411 EnlistedResource resource = 4412 (EnlistedResource) xaResourcesWithHeuristicDecisions.get(i); 4413 resource.forget(); 4414 if (resource.getState() != RS_FORGOT) 4415 success = false; 4416 } 4417 } 4418 4419 if (remoteResourcesWithHeuristicDecisions != null) 4420 { 4421 for (int i = 0; i < remoteResourcesWithHeuristicDecisions.size(); ++i) 4422 { 4423 EnlistedResource resource = 4424 (EnlistedResource) remoteResourcesWithHeuristicDecisions.get(i); 4425 resource.forget(); 4426 if (resource.getState() != RS_FORGOT) 4427 success = false; 4428 } 4429 } 4430 return success; 4431 } 4432 4433 4436 private Xid createXidBranch() 4437 { 4438 long branchId = ++lastBranchId; 4439 4440 return xidFactory.newBranch(xid, branchId); 4441 } 4442 4443 4448 private int getCommitStrategy() 4449 { 4450 int xaResourceCount = xaResources.size(); 4451 int remoteResourceCount = remoteResources.size(); 4452 int resourceCount = xaResourceCount + remoteResourceCount; 4453 4454 if (resourceCount == 0) 4455 return 0; 4456 4457 if (resourceCount == 1) 4458 return 1; 4459 4460 4462 if (remoteResourceCount > 0) 4463 { 4464 return 2; 4467 } 4468 else { 4470 for (int i = 1; i < xaResourceCount; ++i) 4472 { 4473 EnlistedXAResource resource = (EnlistedXAResource) xaResources.get(i); 4474 if (resource.isResourceManager()) 4475 { 4476 return 2; 4479 } 4480 4481 } 4482 return 1; 4484 } 4485 } 4486 4487 4492 private String [] getStringfiedRemoteResourcesThatVotedCommit() 4493 { 4494 List resourcesThatVotedCommit = new ArrayList (remoteResources.size()); 4495 4496 for (int i = 0; i < remoteResources.size(); ++i) 4497 { 4498 EnlistedRemoteResource enlistedRemoteResource = 4499 (EnlistedRemoteResource) remoteResources.get(i); 4500 if (enlistedRemoteResource.getState() == RS_VOTE_OK) 4501 { 4502 Resource r = enlistedRemoteResource.getRemoteResource(); 4503 resourcesThatVotedCommit.add(resourceToString(r)); 4504 } 4505 } 4506 return (String []) resourcesThatVotedCommit.toArray( 4507 new String [resourcesThatVotedCommit.size()]); 4508 } 4509 4510 4515 private void checkWork() 4516 { 4517 if (work != null) 4518 throw new IllegalStateException ("Work still outstanding: " + work + 4519 ", tx=" + toString()); 4520 } 4521 4522 4527 private void sleep(long millis) 4528 { 4529 try 4530 { 4531 unlock(); 4532 Thread.sleep(millis); 4533 } 4534 catch (InterruptedException e) 4535 { 4536 } 4538 finally 4539 { 4540 lock(); 4541 } 4542 } 4543 4544 4546 4550 private interface EnlistedResource 4551 { 4552 public int getState(); 4553 public void remember(int heuristicCode); 4554 int getHeuristicCode(); 4555 public void forget(); 4556 } 4557 4558 4561 private class EnlistedXAResource 4562 implements EnlistedResource 4563 { 4564 4567 private XAResource xaResource; 4568 4569 4572 private int resourceState; 4573 4574 4577 private EnlistedXAResource resourceSameRM; 4578 4579 4582 private Xid resourceXid; 4583 4584 4587 private int heurCode; 4588 4589 4594 private XAResourceAccess xaResourceAccess = null; 4595 4596 4599 public EnlistedXAResource(XAResource xaResource, 4600 Xid resourceXid, 4601 EnlistedXAResource resourceSameRM) 4602 { 4603 this.xaResource = xaResource; 4604 this.resourceXid = resourceXid; 4605 this.resourceSameRM = resourceSameRM; 4606 resourceState = RS_NEW; 4607 heurCode = HEUR_NONE; 4608 } 4609 4610 4614 public EnlistedXAResource(XAWork xaWork) 4615 { 4616 this.xaResource = xaWork.res; 4617 this.resourceXid = xaWork.xid; 4618 this.xaResourceAccess = xaWork.xaResourceAccess; 4619 this.resourceSameRM = null; 4620 resourceState = RS_VOTE_OK; 4621 heurCode = HEUR_NONE; 4622 } 4623 4624 4628 public EnlistedXAResource(XAResource xaResource, 4629 Xid resourceXid, 4630 boolean committed) 4631 { 4632 this.xaResource = xaResource; 4633 this.resourceXid = resourceXid; 4634 this.resourceSameRM = null; 4635 this.resourceState = (committed) ? RS_COMMITTED: RS_ROLLEDBACK; 4636 heurCode = HEUR_UNKNOWN; 4637 } 4638 4639 4642 public XAResource getXAResource() 4643 { 4644 return xaResource; 4645 } 4646 4647 4650 public Xid getXid() 4651 { 4652 return resourceXid; 4653 } 4654 4655 4659 public int getState() 4660 { 4661 return resourceState; 4662 } 4663 4664 4667 public boolean isEnlisted() 4668 { 4669 return resourceState == RS_ENLISTED; 4670 } 4671 4672 4675 public boolean isResourceManager() 4676 { 4677 return resourceSameRM == null; 4678 } 4679 4680 4683 public boolean isResourceManager(XAResource xaRes) 4684 throws XAException 4685 { 4686 return resourceSameRM == null && xaRes.isSameRM(xaResource); 4687 } 4688 4689 4693 public boolean isDelisted(XAResource xaRes) 4694 throws XAException 4695 { 4696 return resourceState == RS_ENDED && xaResource.isSameRM(xaRes) == false; 4697 } 4698 4699 4706 public boolean startResource() 4707 throws XAException 4708 { 4709 int flags = XAResource.TMJOIN; 4710 4711 if (resourceSameRM == null) 4712 { 4713 switch (resourceState) 4714 { 4715 case RS_NEW: 4716 flags = XAResource.TMNOFLAGS; 4717 break; 4718 case RS_SUSPENDED: 4719 flags = XAResource.TMRESUME; 4720 break; 4721 4722 default: 4723 if (trace) 4724 log.trace("Unhandled resource state: " + resourceState + 4725 " (not RS_NEW or RS_SUSPENDED, using TMJOIN flags)"); 4726 } 4727 } 4728 4729 if (trace) 4730 log.trace("startResource(" + 4731 xidFactory.toString(resourceXid) + 4732 ") entered: " + xaResource.toString() + 4733 " flags=" + flags); 4734 4735 unlock(); 4736 try 4738 { 4739 try 4740 { 4741 xaResource.start(resourceXid, flags); 4742 } 4743 catch (XAException e) 4744 { 4745 throw e; 4746 } 4747 catch (Throwable t) 4748 { 4749 if (trace) 4750 log.trace("unhandled throwable error in startResource", 4751 t); 4752 status = Status.STATUS_MARKED_ROLLBACK; 4753 return false; 4754 } 4755 4756 resourceState = RS_ENLISTED; 4758 } 4759 finally 4760 { 4761 lock(); 4762 if (trace) 4763 log.trace("startResource(" + 4764 xidFactory.toString(resourceXid) + 4765 ") leaving: " + xaResource.toString() + 4766 " flags=" + flags); 4767 } 4768 return true; 4769 } 4770 4771 4774 public boolean delistResource(XAResource xaRes, int flag) 4775 throws XAException 4776 { 4777 if (isDelisted(xaRes)) 4778 { 4779 log.warn("Resource already delisted. tx=" + 4782 TransactionImpl.this.toString()); 4783 return false; 4784 } 4785 endResource(flag); 4786 return true; 4787 } 4788 4789 4792 public void endResource() 4793 throws XAException 4794 { 4795 if (resourceState == RS_ENLISTED || resourceState == RS_SUSPENDED) 4796 { 4797 if (trace) 4798 log.trace("endresources(" + xaResource + "): state=" + 4799 resourceState); 4800 endResource(XAResource.TMSUCCESS); 4801 } 4802 } 4803 4804 4811 private void endResource(int flag) 4812 throws XAException 4813 { 4814 if (trace) 4815 log.trace("endResource(" + 4816 xidFactory.toString(resourceXid) + 4817 ") entered: " + xaResource.toString() + 4818 " flag=" + flag); 4819 4820 unlock(); 4821 try 4823 { 4824 try 4825 { 4826 xaResource.end(resourceXid, flag); 4827 } 4828 catch (XAException e) 4829 { 4830 throw e; 4831 } 4832 catch (Throwable t) 4833 { 4834 if (trace) 4835 log.trace("unhandled throwable error in endResource", t); 4836 status = Status.STATUS_MARKED_ROLLBACK; 4837 resourceState = RS_ENDED; 4840 return; 4841 } 4842 4843 if (flag == XAResource.TMSUSPEND) 4845 resourceState = RS_SUSPENDED; 4846 else 4847 { 4848 if (flag == XAResource.TMFAIL) 4849 status = Status.STATUS_MARKED_ROLLBACK; 4850 resourceState = RS_ENDED; 4851 } 4852 } 4853 finally 4854 { 4855 lock(); 4856 if (trace) 4857 log.trace("endResource(" + 4858 xidFactory.toString(resourceXid) + 4859 ") leaving: " + xaResource.toString() + 4860 " flag=" + flag); 4861 } 4862 } 4863 4864 4867 public void remember(int heuristicCode) 4868 { 4869 heurCode = heuristicCode; 4870 if (xaResourcesWithHeuristicDecisions == null) 4871 xaResourcesWithHeuristicDecisions = new ArrayList (); 4872 xaResourcesWithHeuristicDecisions.add(this); 4873 } 4874 4875 4878 public int getHeuristicCode() 4879 { 4880 return heurCode; 4881 } 4882 4883 4886 public void forget() 4887 { 4888 unlock(); 4889 if (trace) 4890 log.trace("Forget: " + xaResource + 4891 " xid=" + xidFactory.toString(resourceXid)); 4892 try 4893 { 4894 xaResource.forget(resourceXid); 4895 resourceState = RS_FORGOT; 4896 } 4897 catch (XAException xae) 4898 { 4899 logXAException(xae); 4900 cause = xae; 4901 if (xae.errorCode == XAException.XAER_NOTA) 4902 { 4903 if (trace) 4904 log.trace("XAER_NOTA in forget: " + xaResource + 4905 " xid=" + xidFactory.toString(resourceXid) + 4906 "\nAssuming that the xid has been previously " + 4907 "forgotten.", xae); 4908 resourceState = RS_FORGOT; 4909 } 4910 } 4911 finally 4912 { 4913 lock(); 4914 } 4915 } 4916 4917 4920 public int prepare() 4921 throws XAException 4922 { 4923 int vote; 4924 unlock(); 4925 if (trace) 4926 log.trace("Prepare: " + xaResource + 4927 " xid=" + xidFactory.toString(resourceXid)); 4928 try 4929 { 4930 vote = xaResource.prepare(resourceXid); 4931 4932 if (vote == XAResource.XA_OK) 4933 resourceState = RS_VOTE_OK; 4934 else if (vote == XAResource.XA_RDONLY) 4935 resourceState = RS_VOTE_READONLY; 4936 } 4937 catch (XAException e) 4938 { 4939 if (e.errorCode >= XAException.XA_RBBASE 4940 && e.errorCode <= XAException.XA_RBEND) 4941 { 4942 if (trace) 4943 log.trace("Got rollback vote from XAResource " + xaResource + 4944 " xid=" + xidFactory.toString(resourceXid) + 4945 ", tx=" + TransactionImpl.this.toString() + 4946 ", errorCode=" + 4947 TxUtils.getXAErrorCodeAsString(e.errorCode), e); 4948 4949 resourceState = RS_ROLLEDBACK; 4950 } 4951 else 4952 throw e; 4953 } 4954 finally 4955 { 4956 lock(); 4957 } 4958 return resourceState; 4959 } 4960 4961 4964 public void prepareLastResource() 4965 throws XAException 4966 { 4967 resourceState = RS_VOTE_OK; 4968 } 4969 4970 4973 public void commit(boolean onePhase) 4974 throws XAException 4975 { 4976 if (!onePhase && resourceState != RS_VOTE_OK) 4977 return; 4979 if (resourceSameRM != null) 4980 return; 4982 unlock(); 4983 if (trace) 4984 log.trace("Commit: " + xaResource + 4985 " xid=" + xidFactory.toString(resourceXid) + 4986 " onePhase=" + onePhase); 4987 try 4988 { 4989 xaResource.commit(resourceXid, onePhase); 4990 committedResources++; 4991 resourceState = RS_COMMITTED; 4992 } 4993 catch (XAException e) 4994 { 4995 switch (e.errorCode) 4996 { 4997 case XAException.XA_HEURCOM: 4998 logXAException(e); 5001 if (trace) 5002 log.trace("Ignoring XAException.XA_HEURCOM" + 5003 " in XAResource.commit: " + xaResource + 5004 " xid=" + xidFactory.toString(resourceXid) + 5005 " onePhase=" + onePhase); 5006 forget(); 5007 committedResources++; 5008 resourceState = RS_COMMITTED; 5009 break; 5010 case XAException.XAER_RMERR: 5011 case XAException.XA_HEURRB: 5012 rolledbackResources++; 5013 case XAException.XA_HEURMIX: 5015 case XAException.XA_HEURHAZ: 5016 resourceState = RS_HEUR_OUTCOME; 5017 throw e; 5018 case XAException.XAER_RMFAIL: 5019 case XAException.XA_RETRY: 5020 throw e; 5022 case XAException.XAER_NOTA: 5023 case XAException.XAER_INVAL: 5024 case XAException.XAER_PROTO: 5025 default: 5026 resourceState = RS_ERROR; 5028 throw e; 5029 } 5030 } 5031 finally 5032 { 5033 if (xaResourceAccess != null && resourceState != RS_VOTE_OK) 5034 xaResourceAccess.release(); 5035 lock(); 5036 } 5037 } 5038 5039 5042 public void rollback() 5043 throws XAException 5044 { 5045 if (resourceState == RS_VOTE_READONLY || 5046 resourceState == RS_ROLLEDBACK || resourceState == RS_FORGOT) 5047 return; 5048 5049 if (resourceSameRM != null) 5050 return; 5052 unlock(); 5053 if (trace) 5054 log.trace("Rollback: " + xaResource + 5055 " xid=" + xidFactory.toString(resourceXid)); 5056 try 5057 { 5058 xaResource.rollback(resourceXid); 5059 rolledbackResources++; 5060 resourceState = RS_ROLLEDBACK; 5061 } 5062 catch (XAException e) 5063 { 5064 switch (e.errorCode) 5065 { 5066 case XAException.XAER_RMERR: 5067 if (trace) 5070 log.trace("Ignoring XAException.XAER_RMERR" + 5071 " in XAResource.rollback: " + xaResource + 5072 " xid=" + xidFactory.toString(resourceXid)); 5073 rolledbackResources++; 5074 resourceState = RS_ROLLEDBACK; 5075 break; 5076 case XAException.XA_HEURRB: 5077 if (trace) 5080 log.trace("Ignoring XAException.XA_HEURRB" + 5081 " in XAResource.rollback: " + xaResource + 5082 " xid=" + xidFactory.toString(resourceXid)); 5083 forget(); 5084 rolledbackResources++; 5085 resourceState = RS_ROLLEDBACK; 5086 break; 5087 case XAException.XA_HEURCOM: 5088 committedResources++; 5089 case XAException.XA_HEURMIX: 5090 case XAException.XA_HEURHAZ: 5091 resourceState = RS_HEUR_OUTCOME; 5092 throw e; 5093 case XAException.XAER_RMFAIL: 5094 case XAException.XA_RETRY: 5095 throw e; 5097 case XAException.XAER_NOTA: 5098 case XAException.XAER_INVAL: 5099 case XAException.XAER_PROTO: 5100 default: 5101 resourceState = RS_ERROR; 5103 throw e; 5104 } 5105 } 5106 finally 5107 { 5108 if (xaResourceAccess != null && resourceState != RS_VOTE_OK) 5109 xaResourceAccess.release(); 5110 lock(); 5111 } 5112 } 5113 } 5114 5115 5118 private class EnlistedRemoteResource 5119 implements EnlistedResource 5120 { 5121 5124 private Resource remoteResource; 5125 5126 5129 private int resourceState; 5130 5131 5134 private int heurCode; 5135 5136 5139 public EnlistedRemoteResource(Resource remoteResource) 5140 { 5141 this.remoteResource = remoteResource; 5142 resourceState = RS_NEW; 5143 heurCode = HEUR_NONE; 5144 } 5145 5146 5150 public EnlistedRemoteResource(Resource remoteResource, boolean prepared) 5151 { 5152 this.remoteResource = remoteResource; 5153 if (prepared) 5154 resourceState = RS_VOTE_OK; 5155 else 5156 resourceState = RS_NEW; 5157 heurCode = HEUR_NONE; 5158 } 5159 5160 5164 public EnlistedRemoteResource(Resource remoteResource, 5165 boolean committed, 5166 int heurCode) 5167 { 5168 this.remoteResource = remoteResource; 5169 resourceState = (committed) ? RS_COMMITTED : RS_ROLLEDBACK; 5170 this.heurCode = heurCode; 5171 } 5172 5173 5177 public Resource getRemoteResource() 5178 { 5179 return remoteResource; 5180 } 5181 5182 5186 public int getState() 5187 { 5188 return resourceState; 5189 } 5190 5191 5194 public int prepare() 5195 throws RemoteException , 5196 TransactionAlreadyPreparedException, 5197 HeuristicMixedException , 5198 HeuristicHazardException 5199 { 5200 Vote vote = null; 5201 unlock(); 5202 try 5203 { 5204 vote = remoteResource.prepare(); 5205 } 5206 finally 5207 { 5208 lock(); 5209 } 5210 5211 if (vote == Vote.COMMIT) 5212 resourceState = RS_VOTE_OK; 5213 else if (vote == Vote.READONLY) 5214 resourceState = RS_VOTE_READONLY; 5215 else 5216 resourceState = RS_ROLLEDBACK; 5217 5218 return resourceState; 5219 } 5220 5221 5231 public void commit(boolean onePhase) 5232 throws RemoteException , 5233 TransactionNotPreparedException, 5234 HeuristicRollbackException , 5235 HeuristicMixedException , 5236 HeuristicHazardException 5237 { 5238 if (trace) 5239 log.trace("Committing resource " + remoteResource + 5240 " state=" + resourceState); 5241 5242 if (!onePhase && resourceState != RS_VOTE_OK) 5243 return; 5245 unlock(); 5246 try 5247 { 5248 if (onePhase) 5249 remoteResource.commitOnePhase(); 5250 else 5251 remoteResource.commit(); 5252 5253 committedResources++; 5254 resourceState = RS_COMMITTED; 5255 } 5256 catch (TransactionRolledbackException e) 5257 { 5258 rolledbackResources++; 5259 resourceState = RS_ROLLEDBACK; 5260 throw e; 5261 } 5262 catch (RemoteException e) 5263 { 5264 throw e; 5266 } 5267 catch (TransactionNotPreparedException e) 5268 { 5269 resourceState = RS_ERROR; 5270 throw e; 5271 } 5272 catch (HeuristicRollbackException e) 5273 { 5274 rolledbackResources++; 5275 resourceState = RS_HEUR_OUTCOME; 5276 throw e; 5277 } 5278 catch (HeuristicMixedException e) 5279 { 5280 resourceState = RS_HEUR_OUTCOME; 5281 throw e; 5282 } 5283 catch (HeuristicHazardException e) 5284 { 5285 resourceState = RS_HEUR_OUTCOME; 5286 throw e; 5287 } 5288 finally 5289 { 5290 lock(); 5291 } 5292 } 5293 5294 5297 public void rollback() 5298 throws RemoteException , 5299 HeuristicCommitException , 5300 HeuristicMixedException , 5301 HeuristicHazardException 5302 { 5303 if (resourceState == RS_VOTE_READONLY || 5304 resourceState == RS_ROLLEDBACK || resourceState == RS_FORGOT) 5305 return; 5306 5307 unlock(); 5308 try 5309 { 5310 remoteResource.rollback(); 5311 rolledbackResources++; 5312 resourceState = RS_ROLLEDBACK; 5313 } 5314 catch (TransactionRolledbackException e) 5315 { 5316 rolledbackResources++; 5317 resourceState = RS_ROLLEDBACK; 5318 throw e; 5319 } 5320 catch (RemoteException e) 5321 { 5322 throw e; 5324 } 5325 catch (HeuristicCommitException e) 5326 { 5327 committedResources++; 5328 resourceState = RS_HEUR_OUTCOME; 5329 throw e; 5330 } 5331 catch (HeuristicMixedException e) 5332 { 5333 resourceState = RS_HEUR_OUTCOME; 5334 throw e; 5335 } 5336 catch (HeuristicHazardException e) 5337 { 5338 resourceState = RS_HEUR_OUTCOME; 5339 throw e; 5340 } 5341 finally 5342 { 5343 lock(); 5344 } 5345 } 5346 5347 5350 public void remember(int heuristicCode) 5351 { 5352 heurCode = heuristicCode; 5353 if (remoteResourcesWithHeuristicDecisions == null) 5354 remoteResourcesWithHeuristicDecisions = new ArrayList (); 5355 remoteResourcesWithHeuristicDecisions.add(this); 5356 } 5357 5358 5361 public int getHeuristicCode() 5362 { 5363 return heurCode; 5364 } 5365 5366 5369 public void forget() 5370 { 5371 unlock(); 5372 if (trace) 5373 log.trace("Forget: " + remoteResource); 5374 try 5375 { 5376 remoteResource.forget(); 5377 resourceState = RS_FORGOT; 5378 } 5379 catch (NoSuchObjectException e) 5380 { 5381 if (trace) 5382 log.trace("NoSuchObjectException in forget: remoteResource=" + 5383 remoteResource + "\nAssuming that the resource has " + 5384 "been previously forgotten.", e); 5385 } 5386 catch (RemoteException e) 5387 { 5388 if (trace) 5389 log.trace("RemoteException in forget: remoteResource=" + 5390 remoteResource + "\nThe resource still needs to be " + 5391 "forgotten.", e); 5392 } 5393 finally 5394 { 5395 lock(); 5396 } 5397 resourceState = RS_FORGOT; 5398 } 5399 5400 } 5401 5402} 5403 | Popular Tags |