1 21 22 package org.apache.derby.impl.store.raw.xact; 23 24 import org.apache.derby.iapi.services.context.ContextManager; 25 26 import org.apache.derby.iapi.services.sanity.SanityManager; 27 import org.apache.derby.iapi.services.io.Formatable; 28 import org.apache.derby.iapi.services.io.FormatIdUtil; 29 import org.apache.derby.iapi.services.io.StoredFormatIds; 30 31 import org.apache.derby.iapi.store.access.TransactionInfo; 32 33 import org.apache.derby.iapi.store.raw.GlobalTransactionId; 34 35 import org.apache.derby.iapi.store.raw.log.LogInstant; 36 37 import org.apache.derby.iapi.store.raw.xact.RawTransaction; 38 import org.apache.derby.iapi.store.raw.xact.TransactionId; 39 40 import org.apache.derby.iapi.error.StandardException; 41 42 import org.apache.derby.iapi.services.io.CompressedNumber; 43 44 import java.util.Hashtable ; 45 import java.util.Enumeration ; 46 import java.io.ObjectOutput ; 47 import java.io.ObjectInput ; 48 import java.io.IOException ; 49 50 87 88 public class TransactionTable implements Formatable 89 { 90 93 94 private Hashtable trans; 95 96 private TransactionId largestUpdateXactId; 97 98 101 public TransactionTable() 102 { 103 trans = new Hashtable (17); 104 } 105 106 110 private TransactionTableEntry findTransactionEntry(TransactionId id) 111 { 112 113 if (SanityManager.DEBUG) 114 SanityManager.ASSERT( 115 id != null, "findTransacionEntry with null id"); 116 117 return (TransactionTableEntry)trans.get(id); 119 } 120 121 122 123 124 void add(Xact xact, boolean exclude) 125 { 126 TransactionId id = xact.getId(); 127 128 synchronized(this) 129 { 130 TransactionTableEntry ent = findTransactionEntry(id); 131 132 if (ent == null) 133 { 134 ent = new TransactionTableEntry 135 (xact, id, 0, 136 exclude ? TransactionTableEntry.EXCLUDE : 0); 137 138 trans.put(id, ent); 139 140 if (SanityManager.DEBUG) 141 { 142 if (SanityManager.DEBUG_ON("TranTrace")) 143 { 144 SanityManager.DEBUG( 145 "TranTrace", "adding transaction " + id); 146 SanityManager.showTrace(new Throwable ("TranTrace")); 147 } 148 } 149 } 150 151 if (SanityManager.DEBUG) 152 { 153 if (exclude != ent.needExclusion()) 154 SanityManager.THROWASSERT( 155 "adding the same transaction with different exclusion: " + 156 exclude + " " + ent.needExclusion()); 157 } 158 } 159 160 if (SanityManager.DEBUG) { 161 162 if (SanityManager.DEBUG_ON("memoryLeakTrace")) { 163 164 if (trans.size() > 50) 165 System.out.println("memoryLeakTrace:TransactionTable " + trans.size()); 166 } 167 } 168 } 169 170 174 boolean remove(TransactionId id) 175 { 176 if (SanityManager.DEBUG) 177 SanityManager.ASSERT( 178 id != null, 179 "cannot remove transaction from table with null id"); 180 181 if (SanityManager.DEBUG) 182 { 183 if (SanityManager.DEBUG_ON("TranTrace")) 184 { 185 SanityManager.DEBUG( 186 "TranTrace", "removing transaction " + id); 187 SanityManager.showTrace(new Throwable ("TranTrace")); 188 } 189 } 190 191 TransactionTableEntry ent = (TransactionTableEntry)trans.remove(id); 193 return (ent == null || ent.needExclusion()); 194 } 195 196 197 205 public void addUpdateTransaction(TransactionId tid, RawTransaction tran, 206 int transactionStatus) 207 { 208 209 synchronized(this) 215 { 216 TransactionTableEntry ent = findTransactionEntry(tid); 217 218 if (ent != null) 219 { 220 223 ent.updateTransactionStatus((Xact)tran, transactionStatus, 224 TransactionTableEntry.UPDATE) ; 225 } 226 else 227 { 228 ent = new TransactionTableEntry((Xact)tran, tid, transactionStatus, 235 TransactionTableEntry.UPDATE | 236 TransactionTableEntry.EXCLUDE | 237 TransactionTableEntry.RECOVERY); 238 trans.put(tid, ent); 239 240 } 241 242 if (XactId.compare(ent.getXid(), largestUpdateXactId) > 0) 243 largestUpdateXactId = ent.getXid(); 244 } 245 } 246 247 254 void removeUpdateTransaction(TransactionId id) 255 { 256 262 synchronized (this) 263 { 264 TransactionTableEntry ent = findTransactionEntry(id); 265 266 if (SanityManager.DEBUG) 267 { 268 SanityManager.ASSERT(ent != null, 269 "removing update transaction that is not there"); 270 } 271 272 ent.removeUpdateTransaction(); 273 274 if (ent.isRecovery()) 278 remove(id); 279 } 280 281 return; 282 } 283 284 288 289 305 public Hashtable getTableForXA() 306 { 307 return(trans); 308 } 309 310 317 void prepareTransaction(TransactionId id) 318 { 319 325 TransactionTableEntry ent = findTransactionEntry(id); 326 327 if (SanityManager.DEBUG) 328 { 329 SanityManager.ASSERT( 330 ent != null, "preparing transaction that is not there"); 331 } 332 333 ent.prepareTransaction(); 334 335 return; 336 } 337 338 350 public ContextManager findTransactionContextByGlobalId( 351 GlobalXactId global_id) 352 { 353 ContextManager cm = null; 354 355 synchronized (trans) 357 { 358 for (Enumeration e = trans.elements(); e.hasMoreElements();) 359 { 360 TransactionTableEntry entry = 361 (TransactionTableEntry) e.nextElement(); 362 363 if (entry != null) 364 { 365 GlobalTransactionId entry_gid = entry.getGid(); 366 367 if (entry_gid != null && entry_gid.equals(global_id)) 368 { 369 cm = entry.getXact().getContextManager(); 370 break; 371 } 372 } 373 } 374 } 375 376 return(cm); 377 } 378 379 380 383 391 boolean hasActiveUpdateTransaction() 392 { 393 synchronized (this) 394 { 395 for (Enumeration e = trans.elements(); e.hasMoreElements(); ) 396 { 397 TransactionTableEntry ent = (TransactionTableEntry)e.nextElement(); 398 if (ent != null && ent.isUpdate()) 399 return true; 400 } 401 } 402 return false; 403 } 404 405 406 407 410 413 414 417 public int getTypeFormatId() { 418 return StoredFormatIds.RAW_STORE_TRANSACTION_TABLE; 419 } 420 421 424 public void writeExternal(ObjectOutput out) throws IOException 425 { 426 433 synchronized(this) 434 { 435 synchronized(trans) 437 { 438 int count = 0; 439 int maxcount = trans.size(); 440 441 for (Enumeration e = trans.elements(); 443 e.hasMoreElements(); ) 444 { 445 TransactionTableEntry ent = (TransactionTableEntry)e.nextElement(); 446 if (ent != null && ent.isUpdate()) 447 count++; 448 } 449 450 CompressedNumber.writeInt(out, count); 451 452 if (count > 0) 454 { 455 for (Enumeration e = trans.elements(); 456 e.hasMoreElements() ; ) 457 { 458 TransactionTableEntry ent = (TransactionTableEntry)e.nextElement(); 459 if (ent != null && ent.isUpdate()) 460 { 461 out.writeObject(ent); 463 } 464 } 465 } 466 } 467 } 468 } 469 470 473 474 475 479 public void readExternal(ObjectInput in) 480 throws IOException , ClassNotFoundException 481 { 482 486 int count = CompressedNumber.readInt(in); 487 if (count == 0) 488 return; 489 490 for (int i = 0; i < count; i++) 491 { 492 TransactionTableEntry ent = 493 (TransactionTableEntry)in.readObject(); 494 495 if (SanityManager.DEBUG) 496 SanityManager.ASSERT( 497 ent.getXid() != null, 498 "read in transaction table entry with null id"); 499 500 trans.put(ent.getXid(), ent); 501 502 if (ent.isUpdate() && 503 XactId.compare(ent.getXid(), largestUpdateXactId) > 0) 504 { 505 largestUpdateXactId = ent.getXid(); 506 } 507 } 508 509 510 } 511 512 517 public TransactionId largestUpdateXactId() 518 { 519 return largestUpdateXactId; 520 } 521 522 523 528 public boolean hasRollbackFirstTransaction() 529 { 530 for (Enumeration e = trans.elements(); 531 e.hasMoreElements() ; ) 532 { 533 TransactionTableEntry ent = (TransactionTableEntry)e.nextElement(); 534 535 if (ent != null && ent.isRecovery() && 536 (ent.getTransactionStatus() & 537 Xact.RECOVERY_ROLLBACK_FIRST) != 0) 538 { 539 return true; 540 } 541 } 542 return false; 543 } 544 545 551 public boolean hasPreparedRecoveredXact() 552 { 553 return hasPreparedXact(true); 554 } 555 556 557 561 public boolean hasPreparedXact() 562 { 563 return hasPreparedXact(false); 564 } 565 566 580 581 private boolean hasPreparedXact(boolean recovered) 582 { 583 for (Enumeration e = trans.elements(); e.hasMoreElements(); ) 584 { 585 TransactionTableEntry ent = (TransactionTableEntry) e.nextElement(); 586 587 if (ent != null && 588 (ent.getTransactionStatus() & Xact.END_PREPARED) != 0) 589 { 590 if (recovered) { 591 if(ent.isRecovery()) 592 return true; 593 } else { 594 return true; 595 } 596 } 597 } 598 return false; 599 } 600 601 602 603 604 615 public boolean getMostRecentRollbackFirstTransaction(RawTransaction tran) 616 { 617 618 if (trans.isEmpty()) 619 { 620 return findAndAssumeTransaction((TransactionId)null, tran); 622 } 623 624 TransactionId id = null; 625 for (Enumeration e = trans.elements(); 626 e.hasMoreElements() ; ) 627 { 628 TransactionTableEntry ent = (TransactionTableEntry)e.nextElement(); 629 630 if (ent != null && ent.isUpdate() && ent.isRecovery() && 631 (ent.getTransactionStatus() & Xact.RECOVERY_ROLLBACK_FIRST) != 0) 632 { 633 if (id == null || XactId.compare(id, ent.getXid()) < 0) 635 id = ent.getXid(); 636 } 637 } 638 639 if (id == null) { 641 return findAndAssumeTransaction(id, tran); 642 } 643 else 644 { 645 boolean found = 647 findAndAssumeTransaction(id, tran); 648 649 if (SanityManager.DEBUG) 650 { 651 if (!found) 652 { 653 SanityManager.THROWASSERT( 654 "cannot find transaction " + id + " in table"); 655 } 656 } 657 658 return true; 659 } 660 } 661 662 674 public boolean getMostRecentTransactionForRollback(RawTransaction tran) 675 { 676 TransactionId id = null; 677 678 if (!trans.isEmpty()) 679 { 680 for (Enumeration e = trans.elements(); 681 e.hasMoreElements() ; ) 682 { 683 TransactionTableEntry ent = 684 (TransactionTableEntry)e.nextElement(); 685 686 if (ent != null && 687 ent.isUpdate() && 688 ent.isRecovery() && 689 !ent.isPrepared()) 690 { 691 if (id == null || XactId.compare(id, ent.getXid()) < 0) 693 id = ent.getXid(); 694 } 695 696 if (SanityManager.DEBUG) 697 { 698 if (ent != null && 699 ent.isUpdate() && 700 ent.isRecovery() && 701 (ent.getTransactionStatus() & 702 Xact.RECOVERY_ROLLBACK_FIRST) != 0) 703 { 704 SanityManager.THROWASSERT( 705 "still rollback first xacts in the tran table!"); 706 } 707 } 708 } 709 710 if (SanityManager.DEBUG) 711 { 712 if (id != null) 715 { 716 SanityManager.ASSERT(findTransactionEntry(id) != null); 717 } 718 else 719 { 720 for (Enumeration e = trans.elements(); e.hasMoreElements();) 722 { 723 TransactionTableEntry ent = 724 (TransactionTableEntry)e.nextElement(); 725 SanityManager.ASSERT(ent.isPrepared()); 726 } 727 } 728 } 729 } 730 731 return(findAndAssumeTransaction(id, tran)); 732 } 733 734 742 743 768 public boolean getMostRecentPreparedRecoveredXact( 769 RawTransaction tran) 770 { 771 TransactionTableEntry found_ent = null; 772 773 if (!trans.isEmpty()) 774 { 775 TransactionId id = null; 776 GlobalTransactionId gid = null; 777 TransactionTableEntry ent; 778 779 for (Enumeration e = trans.elements(); e.hasMoreElements(); ) 780 { 781 ent = (TransactionTableEntry)e.nextElement(); 782 783 if (ent != null && 784 ent.isRecovery() && 785 ent.isPrepared()) 786 { 787 if (id == null || XactId.compare(id, ent.getXid()) < 0) 789 { 790 found_ent = ent; 791 id = ent.getXid(); 792 gid = ent.getGid(); 793 } 794 } 795 } 796 797 if (SanityManager.DEBUG) 798 { 799 if (found_ent == null) 800 { 801 for (Enumeration e = trans.elements(); e.hasMoreElements();) 805 { 806 ent = (TransactionTableEntry)e.nextElement(); 807 808 if (XactId.compare(ent.getXid(), tran.getId()) != 0) 809 { 810 SanityManager.ASSERT( 811 !ent.isRecovery() && ent.isPrepared()); 812 SanityManager.ASSERT(ent.getGid() != null); 813 } 814 } 815 } 816 } 817 818 if (found_ent != null) 819 { 820 TransactionTableEntry new_ent = 829 (TransactionTableEntry) trans.remove(tran.getId()); 830 831 if (SanityManager.DEBUG) 833 { 834 SanityManager.ASSERT(findTransactionEntry(id) == found_ent); 835 } 836 837 ((Xact) tran).assumeGlobalXactIdentity(found_ent); 838 839 found_ent.unsetRecoveryStatus(); 841 } 842 } 843 844 return(found_ent != null); 845 } 846 847 853 public LogInstant getFirstLogInstant() 854 { 855 858 if (trans.isEmpty()) 859 { 860 return null; 861 } 862 else 863 { 864 LogInstant logInstant = null; 865 866 871 synchronized (trans) 872 { 873 for (Enumeration e = trans.elements(); e.hasMoreElements(); ) 874 { 875 TransactionTableEntry ent = 876 (TransactionTableEntry)e.nextElement(); 877 878 if (ent != null && ent.isUpdate()) 879 { 880 if (logInstant == null || 881 ent.getFirstLog().lessThan(logInstant)) 882 { 883 logInstant = ent.getFirstLog(); 884 } 885 } 886 } 887 } 888 889 return logInstant; 890 } 891 } 892 893 904 boolean findAndAssumeTransaction( 905 TransactionId id, 906 RawTransaction tran) 907 { 908 TransactionTableEntry ent = null; 911 912 if (id != null && !trans.isEmpty()) 913 { 914 ent = findTransactionEntry(id); 915 916 if (SanityManager.DEBUG) 917 { 918 if (ent != null) 919 SanityManager.ASSERT(ent.isRecovery(), 920 "assuming the id of a non-recovery transaction"); 921 } 922 } 923 924 ((Xact)tran).assumeIdentity(ent); 926 927 return(ent != null); 928 929 } 930 931 935 936 939 public TransactionInfo[] getTransactionInfo() 940 { 941 if (trans.isEmpty()) 942 return null; 943 944 TransactionInfo[] tinfo; 946 947 if (SanityManager.DEBUG) 948 SanityManager.DEBUG("TranTrace", toString()); 949 950 synchronized(this) 951 { 952 int ntran = trans.size(); 953 tinfo = new TransactionTableEntry[ntran]; 954 955 LogInstant logInstant = null; 956 int i = 0; 957 958 for (Enumeration e = trans.elements(); 959 e.hasMoreElements(); ) 960 { 961 TransactionTableEntry ent = 962 (TransactionTableEntry)e.nextElement(); 963 964 if (ent != null) 965 tinfo[i++] = (TransactionTableEntry)ent.clone(); 966 967 if (SanityManager.DEBUG) 968 SanityManager.ASSERT(ent != null, "transaction table has null entry"); 969 } 970 } 971 972 return tinfo; 973 } 974 975 public String toString() 976 { 977 if (SanityManager.DEBUG) 978 { 979 StringBuffer str = new StringBuffer (1000). 980 append("\n**************************\n"). 981 append(super.toString()). 982 append("\nTransaction Table: size = ").append(trans.size()). 983 append(" largestUpdateXactId = ").append(largestUpdateXactId). 984 append("\n"); 985 986 boolean hasReadOnlyTransaction = false; 987 988 for (Enumeration e = trans.elements(); 989 e.hasMoreElements(); ) 990 { 991 TransactionTableEntry ent = 992 (TransactionTableEntry)e.nextElement(); 993 994 if (ent != null && ent.isUpdate()) 995 str.append(ent.toString()); 996 997 if (ent != null && !ent.isUpdate()) 998 hasReadOnlyTransaction = true; 999 } 1000 1001 if (hasReadOnlyTransaction) 1002 { 1003 str.append("\n READ ONLY TRANSACTIONS \n"); 1004 1005 for (Enumeration e = trans.elements(); 1006 e.hasMoreElements(); ) 1007 { 1008 TransactionTableEntry ent = 1009 (TransactionTableEntry)e.nextElement(); 1010 1011 if (ent != null && !ent.isUpdate()) 1012 str.append(ent.toString()); 1013 } 1014 } 1015 str.append("---------------------------"); 1016 return str.toString(); 1017 } 1018 else 1019 return null; 1020 } 1021 1022 1023} 1024 1025 | Popular Tags |