1 21 22 package org.apache.derby.impl.store.raw.log; 23 24 import org.apache.derby.iapi.reference.SQLState; 25 import org.apache.derby.iapi.reference.MessageId; 26 27 import org.apache.derby.impl.store.raw.log.LogCounter; 28 import org.apache.derby.impl.store.raw.log.LogRecord; 29 import org.apache.derby.impl.store.raw.log.StreamLogScan; 30 31 import org.apache.derby.iapi.store.access.TransactionController; 32 33 import org.apache.derby.iapi.store.raw.RawStoreFactory; 34 35 import org.apache.derby.iapi.store.raw.log.LogInstant; 36 import org.apache.derby.iapi.store.raw.log.Logger; 37 import org.apache.derby.iapi.store.raw.log.LogScan; 38 39 import org.apache.derby.iapi.store.raw.xact.RawTransaction; 40 import org.apache.derby.iapi.store.raw.xact.TransactionFactory; 41 import org.apache.derby.iapi.store.raw.xact.TransactionId; 42 43 import org.apache.derby.iapi.store.raw.Compensation; 44 import org.apache.derby.iapi.store.raw.ContainerHandle; 45 import org.apache.derby.iapi.store.raw.LockingPolicy; 46 import org.apache.derby.iapi.store.raw.Loggable; 47 import org.apache.derby.iapi.store.raw.Page; 48 import org.apache.derby.iapi.store.raw.RePreparable; 49 import org.apache.derby.iapi.store.raw.Undoable; 50 51 import org.apache.derby.iapi.services.io.FormatIdOutputStream; 52 53 import org.apache.derby.iapi.services.sanity.SanityManager; 54 55 import org.apache.derby.iapi.error.StandardException; 56 import org.apache.derby.iapi.services.i18n.MessageService; 57 58 import org.apache.derby.iapi.services.io.ArrayInputStream; 59 import org.apache.derby.iapi.services.io.ArrayOutputStream; 60 import org.apache.derby.iapi.util.ByteArray; 61 import org.apache.derby.iapi.services.io.DynamicByteArrayOutputStream; 62 63 import org.apache.derby.iapi.services.io.LimitObjectInput; 64 import java.io.IOException ; 65 66 import org.apache.derby.impl.store.raw.data.InitPageOperation; 67 68 115 116 public class FileLogger implements Logger { 117 118 private LogRecord logRecord; 119 120 protected byte[] encryptionBuffer; 121 private DynamicByteArrayOutputStream logOutputBuffer; 122 private FormatIdOutputStream logicalOut; 123 124 private ArrayInputStream logIn; 125 126 private LogToFile logFactory; 128 132 public FileLogger(LogToFile logFactory) { 133 134 this.logFactory = logFactory; 135 logOutputBuffer = new DynamicByteArrayOutputStream(1024); logicalOut = new FormatIdOutputStream(logOutputBuffer); 137 138 logIn = new ArrayInputStream(); 153 154 logRecord = new LogRecord(); 155 156 } 157 158 163 public void close() throws IOException 164 { 165 if (logOutputBuffer != null) 166 { 167 logOutputBuffer.close(); 168 logOutputBuffer = null; 169 } 170 171 logIn = null; 172 logFactory = null; 173 174 logicalOut = null; 175 176 logRecord = null; 177 } 178 179 182 183 202 public synchronized LogInstant logAndDo(RawTransaction xact, Loggable operation) 203 throws StandardException 204 { 205 boolean isLogPrepared = false; 206 207 boolean inUserCode = false; 208 byte[] preparedLog; 209 210 try { 211 212 logOutputBuffer.reset(); 213 214 TransactionId transactionId = xact.getId(); 217 218 logRecord.setValue(transactionId, operation); 222 223 inUserCode = true; 224 logicalOut.writeObject(logRecord); 225 inUserCode = false; 226 227 int optionalDataLength = 0; 228 int optionalDataOffset = 0; 229 int completeLength = 0; 230 231 ByteArray preparedLogArray = operation.getPreparedLog(); 232 if (preparedLogArray != null) { 233 234 preparedLog = preparedLogArray.getArray(); 235 optionalDataLength = preparedLogArray.getLength(); 236 optionalDataOffset = preparedLogArray.getOffset(); 237 238 268 logIn.setData(preparedLog); 272 logIn.setPosition(optionalDataOffset); 273 logIn.setLimit(optionalDataLength); 274 275 if (SanityManager.DEBUG) 276 { 277 if ((optionalDataLength) != logIn.available()) 278 SanityManager.THROWASSERT( 279 " stream not set correctly " + 280 optionalDataLength + " != " + 281 logIn.available()); 282 } 283 284 } else { 285 preparedLog = null; 286 optionalDataLength = 0; 287 } 288 289 logicalOut.writeInt(optionalDataLength); 290 completeLength = logOutputBuffer.getPosition() + optionalDataLength; 291 292 293 LogInstant logInstant = null; 294 int encryptedLength = 0; 296 try 297 { 298 if (logFactory.databaseEncrypted()) 299 { 300 encryptedLength = completeLength; 303 if ((encryptedLength % logFactory.getEncryptionBlockSize()) != 0) 304 encryptedLength = encryptedLength + logFactory.getEncryptionBlockSize() - (encryptedLength % logFactory.getEncryptionBlockSize()); 305 306 if (encryptionBuffer == null || 307 encryptionBuffer.length < encryptedLength) 308 encryptionBuffer = new byte[encryptedLength]; 309 310 System.arraycopy(logOutputBuffer.getByteArray(), 0, 311 encryptionBuffer, 0, completeLength-optionalDataLength); 312 313 if (optionalDataLength > 0) 314 System.arraycopy(preparedLog, optionalDataOffset, 315 encryptionBuffer, 316 completeLength-optionalDataLength, optionalDataLength); 317 318 int len = 320 logFactory.encrypt(encryptionBuffer, 0, encryptedLength, 321 encryptionBuffer, 0); 322 323 if (SanityManager.DEBUG) 324 SanityManager.ASSERT(len == encryptedLength, 325 "encrypted log buffer length != log buffer len"); 326 } 327 328 if ((operation.group() & (Loggable.FIRST | Loggable.LAST)) != 0) 329 { 330 synchronized (logFactory) 331 { 332 long instant = 0; 333 334 if (logFactory.databaseEncrypted()) 335 { 336 instant = logFactory. 339 appendLogRecord(encryptionBuffer, 0, 340 encryptedLength, null, 341 -1, 0); 342 } 343 else 344 { 345 instant = logFactory. 346 appendLogRecord(logOutputBuffer.getByteArray(), 347 0, completeLength, preparedLog, 348 optionalDataOffset, 349 optionalDataLength); 350 } 351 logInstant = new LogCounter(instant); 352 353 operation.doMe(xact, logInstant, logIn); 354 } 355 } 356 else 357 { 358 long instant = 0; 359 360 if (logFactory.databaseEncrypted()) 361 { 362 instant = logFactory. 365 appendLogRecord(encryptionBuffer, 0, 366 encryptedLength, null, -1, 0); 367 } 368 else 369 { 370 instant = logFactory. 371 appendLogRecord(logOutputBuffer.getByteArray(), 0, 372 completeLength, preparedLog, 373 optionalDataOffset, 374 optionalDataLength); 375 } 376 377 logInstant = new LogCounter(instant); 378 379 operation.doMe(xact, logInstant, logIn); 380 } 381 382 } 383 catch (StandardException se) 384 { 385 throw logFactory.markCorrupt( 386 StandardException.newException( 387 SQLState.LOG_DO_ME_FAIL, se, operation)); 388 } 389 catch (IOException ioe) 390 { 391 throw logFactory.markCorrupt( 392 StandardException.newException( 393 SQLState.LOG_DO_ME_FAIL, ioe, operation)); 394 } 395 finally 396 { 397 logIn.clearLimit(); 398 } 399 400 if (SanityManager.DEBUG) 401 { 402 if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) 403 { 404 SanityManager.DEBUG( 405 LogToFile.DBG_FLAG, 406 "Write log record: tranId=" + transactionId.toString() + 407 " instant: " + logInstant.toString() + " length: " + 408 completeLength + "\n" + operation + "\n"); 409 } 410 } 411 return logInstant; 412 } 413 414 catch (IOException ioe) 415 { 416 if (inUserCode) 418 { 419 throw StandardException.newException( 420 SQLState.LOG_WRITE_LOG_RECORD, ioe, operation); 421 } 422 else 423 { 424 throw StandardException.newException( 425 SQLState.LOG_BUFFER_FULL, ioe, operation); 426 } 427 } 428 429 } 430 431 451 public LogInstant logAndUndo(RawTransaction xact, 452 Compensation compensation, 453 LogInstant undoInstant, 454 LimitObjectInput in) 455 throws StandardException 456 { 457 boolean inUserCode = false; 458 459 try { 460 logOutputBuffer.reset(); 461 462 TransactionId transactionId = xact.getId(); 463 464 logRecord.setValue(transactionId, compensation); 466 467 inUserCode = true; 468 logicalOut.writeObject(logRecord); 469 inUserCode = false; 470 471 logicalOut.writeLong(((LogCounter)undoInstant).getValueAsLong()); 473 474 int completeLength = logOutputBuffer.getPosition(); 478 long instant = 0; 479 480 if (logFactory.databaseEncrypted()) 481 { 482 int encryptedLength = completeLength; 485 if ((encryptedLength % logFactory.getEncryptionBlockSize()) != 0) 486 encryptedLength = encryptedLength + logFactory.getEncryptionBlockSize() - (encryptedLength % logFactory.getEncryptionBlockSize()); 487 488 if (encryptionBuffer == null || 489 encryptionBuffer.length < encryptedLength) 490 encryptionBuffer = new byte[encryptedLength]; 491 492 System.arraycopy(logOutputBuffer.getByteArray(), 0, 493 encryptionBuffer, 0, completeLength); 494 495 int len = 497 logFactory.encrypt(encryptionBuffer, 0, encryptedLength, 498 encryptionBuffer, 0); 499 500 if (SanityManager.DEBUG) 501 SanityManager.ASSERT(len == encryptedLength, 502 "encrypted log buffer length != log buffer len"); 503 504 instant = logFactory. 505 appendLogRecord(encryptionBuffer, 506 0, encryptedLength, null, 0, 0); 507 } 508 else 509 { 510 instant = logFactory. 511 appendLogRecord(logOutputBuffer.getByteArray(), 512 0, completeLength, null, 0, 0); 513 } 514 515 LogInstant logInstant = new LogCounter(instant); 516 517 if (SanityManager.DEBUG) 518 { 519 if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) 520 { 521 SanityManager.DEBUG( 522 LogToFile.DBG_FLAG, 523 "Write CLR: Xact: " + transactionId.toString() + 524 "clrinstant: " + logInstant.toString() + 525 " undoinstant " + undoInstant + "\n"); 526 } 527 } 528 529 try 530 { 531 compensation.doMe(xact, logInstant, in); 534 } 535 catch (StandardException se) 536 { 537 throw logFactory.markCorrupt( 538 StandardException.newException( 539 SQLState.LOG_DO_ME_FAIL, se, compensation)); 540 } 541 catch (IOException ioe) 542 { 543 throw logFactory.markCorrupt( 544 StandardException.newException( 545 SQLState.LOG_DO_ME_FAIL, ioe, compensation)); 546 } 547 548 return logInstant; 549 550 } 551 catch (IOException ioe) 552 { 553 if (inUserCode) 554 { 555 throw StandardException.newException( 556 SQLState.LOG_WRITE_LOG_RECORD, ioe, compensation); 557 } 558 else 559 { 560 throw StandardException.newException( 561 SQLState.LOG_BUFFER_FULL, ioe, compensation); 562 } 563 } 564 } 565 566 573 public void flush(LogInstant where) 574 throws StandardException 575 { 576 if (SanityManager.DEBUG) 577 { 578 if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) 579 { 580 SanityManager.DEBUG( 581 LogToFile.DBG_FLAG, "Flush log to " + where.toString()); 582 } 583 } 584 585 logFactory.flush(where); 586 } 587 588 595 public void flushAll () throws StandardException 596 { 597 logFactory.flushAll(); 598 } 599 600 622 public void reprepare( 623 RawTransaction t, 624 TransactionId prepareId, 625 LogInstant prepareStopAt, 626 LogInstant prepareStartAt) 627 throws StandardException 628 { 629 630 if (SanityManager.DEBUG) 631 { 632 if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) 633 { 634 if (prepareStartAt != null) 635 { 636 SanityManager.DEBUG( 637 LogToFile.DBG_FLAG, 638 "----------------------------------------------------\n" + 639 "\nBegin of RePrepare : " + prepareId.toString() + 640 "start at " + prepareStartAt.toString() + 641 " stop at " + prepareStopAt.toString() + 642 "\n----------------------------------------------------\n"); 643 } 644 else 645 { 646 SanityManager.DEBUG( 647 LogToFile.DBG_FLAG, 648 "----------------------------------------------------\n" + 649 "\nBegin of Reprepare: " + prepareId.toString() + 650 "start at end of log stop at " + 651 prepareStopAt.toString() + 652 "\n----------------------------------------------------\n"); 653 } 654 } 655 } 656 657 int clrskipped = 0; 659 int logrecordseen = 0; 660 661 RePreparable lop = null; 662 663 ArrayInputStream rawInput = null; 666 667 try 668 { 669 StreamLogScan scanLog; 670 671 if (prepareStartAt == null) 672 { 673 scanLog = 675 (StreamLogScan) logFactory.openBackwardsScan(prepareStopAt); 676 } 677 else 678 { 679 if (prepareStartAt.lessThan(prepareStopAt)) 680 { 681 return; 683 } 684 685 scanLog = (StreamLogScan) 686 logFactory.openBackwardsScan( 687 ((LogCounter) prepareStartAt).getValueAsLong(), 688 prepareStopAt); 689 } 690 691 if (SanityManager.DEBUG) 692 SanityManager.ASSERT( 693 scanLog != null, "cannot open log for prepare"); 694 695 rawInput = new ArrayInputStream(new byte[4096]); 696 697 LogRecord record; 698 699 while ((record = 700 scanLog.getNextRecord(rawInput, prepareId, 0)) 701 != null) 702 { 703 if (SanityManager.DEBUG) 704 { 705 SanityManager.ASSERT( 706 record.getTransactionId().equals(prepareId), 707 "getNextRecord return unqualified log rec for prepare"); 708 } 709 710 logrecordseen++; 711 712 if (record.isCLR()) 713 { 714 clrskipped++; 715 716 record.skipLoggable(); 718 719 long prepareInstant = rawInput.readLong(); 721 722 if (SanityManager.DEBUG) 723 { 724 if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) 725 { 726 SanityManager.DEBUG( 727 LogToFile.DBG_FLAG, 728 "Skipping over CLRs, reset scan to " + 729 LogCounter.toDebugString(prepareInstant)); 730 } 731 } 732 733 scanLog.resetPosition(new LogCounter(prepareInstant)); 734 740 continue; 741 } 742 743 if (record.requiresPrepareLocks()) 744 { 745 lop = record.getRePreparable(); 746 } 747 else 748 { 749 continue; 750 } 751 752 if (lop != null) 753 { 754 759 lop.reclaimPrepareLocks( 760 t, 761 t.newLockingPolicy( 762 LockingPolicy.MODE_RECORD, 763 TransactionController.ISOLATION_REPEATABLE_READ, 764 true)); 765 766 if (SanityManager.DEBUG) 767 { 768 if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) 769 { 770 SanityManager.DEBUG( 771 LogToFile.DBG_FLAG, 772 "Reprepare log record at instant " + 773 scanLog.getInstant() + " : " + lop); 774 } 775 } 776 777 } 778 } 779 780 } 781 catch (ClassNotFoundException cnfe) 782 { 783 throw logFactory.markCorrupt( 784 StandardException.newException(SQLState.LOG_CORRUPTED, cnfe)); 785 } 786 catch (IOException ioe) 787 { 788 throw logFactory.markCorrupt( 789 StandardException.newException( 790 SQLState.LOG_READ_LOG_FOR_UNDO, ioe)); 791 } 792 catch (StandardException se) 793 { 794 throw 795 logFactory.markCorrupt( 796 StandardException.newException( 797 SQLState.LOG_UNDO_FAILED, se, 798 prepareId, lop, (Object ) null)); 799 } 800 finally 801 { 802 if (rawInput != null) 803 { 804 try 805 { 806 rawInput.close(); 807 } 808 catch (IOException ioe) 809 { 810 throw logFactory.markCorrupt( 811 StandardException.newException( 812 SQLState.LOG_READ_LOG_FOR_UNDO, ioe, prepareId)); 813 } 814 } 815 } 816 817 if (SanityManager.DEBUG) 818 { 819 if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) 820 { 821 SanityManager.DEBUG(LogToFile.DBG_FLAG, "Finish prepare" + 822 ", clr skipped = " + clrskipped + 823 ", record seen = " + logrecordseen + "\n"); 824 } 825 } 826 827 if (SanityManager.DEBUG) 828 { 829 if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) 830 { 831 SanityManager.DEBUG( 832 LogToFile.DBG_FLAG, 833 "----------------------------------------------------\n" + 834 "End of recovery rePrepare\n" + 835 ", clr skipped = " + clrskipped + 836 ", record seen = " + logrecordseen + 837 "\n----------------------------------------------------\n"); 838 } 839 } 840 } 841 842 843 862 public void undo( 863 RawTransaction t, 864 TransactionId undoId, 865 LogInstant undoStopAt, 866 LogInstant undoStartAt) 867 throws StandardException 868 { 869 870 if (SanityManager.DEBUG) 871 { 872 if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) 873 { 874 if (undoStartAt != null) 875 { 876 SanityManager.DEBUG( 877 LogToFile.DBG_FLAG, 878 "\nUndo transaction: " + undoId.toString() + 879 "start at " + undoStartAt.toString() + 880 " stop at " + undoStopAt.toString() ); 881 } 882 else 883 { 884 SanityManager.DEBUG( 885 LogToFile.DBG_FLAG, 886 "\nUndo transaction: " + undoId.toString() + 887 "start at end of log stop at " + undoStopAt.toString()); 888 } 889 } 890 } 891 892 int clrgenerated = 0; 894 int clrskipped = 0; 895 int logrecordseen = 0; 896 897 StreamLogScan scanLog; 898 Compensation compensation = null; 899 Undoable lop = null; 900 901 ArrayInputStream rawInput = null; 904 905 try 906 { 907 if (undoStartAt == null) 908 { 909 911 scanLog = (StreamLogScan) 912 logFactory.openBackwardsScan(undoStopAt); 913 } 914 else 915 { 916 if (undoStartAt.lessThan(undoStopAt)) 917 { 918 return; 920 } 921 922 long undoStartInstant = 923 ((LogCounter) undoStartAt).getValueAsLong(); 924 925 scanLog = (StreamLogScan) 926 logFactory.openBackwardsScan(undoStartInstant, undoStopAt); 927 } 928 929 if (SanityManager.DEBUG) 930 SanityManager.ASSERT( 931 scanLog != null, "cannot open log for undo"); 932 933 rawInput = new ArrayInputStream(new byte[4096]); 934 935 LogRecord record; 936 937 while ((record = 938 scanLog.getNextRecord(rawInput, undoId, 0)) 939 != null) 940 { 941 if (SanityManager.DEBUG) 942 { 943 SanityManager.ASSERT( 944 record.getTransactionId().equals(undoId), 945 "getNextRecord return unqualified log record for undo"); 946 } 947 948 logrecordseen++; 949 950 if (record.isCLR()) 951 { 952 clrskipped++; 953 954 record.skipLoggable(); 956 957 long undoInstant = rawInput.readLong(); 959 960 if (SanityManager.DEBUG) 961 { 962 if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) 963 { 964 SanityManager.DEBUG( 965 LogToFile.DBG_FLAG, 966 "Skipping over CLRs, reset scan to " + 967 LogCounter.toDebugString(undoInstant)); 968 } 969 } 970 971 972 scanLog.resetPosition(new LogCounter(undoInstant)); 973 974 980 continue; 981 } 982 983 lop = record.getUndoable(); 984 985 if (lop != null) 986 { 987 int optionalDataLength = rawInput.readInt(); 988 int savePosition = rawInput.getPosition(); 989 rawInput.setLimit(savePosition, optionalDataLength); 990 991 compensation = lop.generateUndo(t, rawInput); 992 993 if (SanityManager.DEBUG) 994 { 995 if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) 996 { 997 SanityManager.DEBUG( 998 LogToFile.DBG_FLAG, 999 "Rollback log record at instant " + 1000 LogCounter.toDebugString(scanLog.getInstant()) + 1001 " : " + lop); 1002 } 1003 } 1004 1005 clrgenerated++; 1006 1007 if (compensation != null) 1008 { 1009 rawInput.setLimit(savePosition, optionalDataLength); 1012 1013 t.logAndUndo( 1016 compensation, new LogCounter(scanLog.getInstant()), 1017 rawInput); 1018 1019 compensation.releaseResource(t); 1020 compensation = null; 1021 } 1022 1023 } 1025 } 1028 } 1029 catch (ClassNotFoundException cnfe) 1030 { 1031 throw logFactory.markCorrupt( 1032 StandardException.newException(SQLState.LOG_CORRUPTED, cnfe)); 1033 } 1034 catch (IOException ioe) 1035 { 1036 throw logFactory.markCorrupt( 1037 StandardException.newException( 1038 SQLState.LOG_READ_LOG_FOR_UNDO, ioe)); 1039 } 1040 catch (StandardException se) 1041 { 1042 1046 throw logFactory.markCorrupt( 1047 StandardException.newException( 1048 SQLState.LOG_UNDO_FAILED, se, undoId, lop, compensation)); 1049 } 1050 finally 1051 { 1052 if (compensation != null) 1053 { 1054 compensation.releaseResource(t); 1056 } 1057 1058 if (rawInput != null) 1059 { 1060 try 1061 { 1062 rawInput.close(); 1063 } 1064 catch (IOException ioe) 1065 { 1066 throw logFactory.markCorrupt( 1067 StandardException.newException( 1068 SQLState.LOG_READ_LOG_FOR_UNDO, ioe, undoId)); 1069 } 1070 } 1071 } 1072 1073 if (SanityManager.DEBUG) 1074 { 1075 if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) 1076 { 1077 SanityManager.DEBUG( 1078 LogToFile.DBG_FLAG, 1079 "Finish undo" + 1080 ", clr generated = " + clrgenerated + 1081 ", clr skipped = " + clrskipped + 1082 ", record seen = " + logrecordseen + "\n"); 1083 } 1084 } 1085 } 1086 1087 1088 1121 protected long redo( 1122 RawTransaction recoveryTransaction, 1123 TransactionFactory transFactory, 1124 StreamLogScan redoScan, 1125 long redoLWM, 1126 long ttabInstant) 1127 throws IOException , StandardException, ClassNotFoundException 1128 { 1129 if (SanityManager.DEBUG) 1131 { 1132 if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) 1133 { 1134 SanityManager.DEBUG( 1135 LogToFile.DBG_FLAG, 1136 "In recovery redo, redoLWM = " + redoLWM); 1137 } 1138 } 1139 1140 int scanCount = 0; 1141 int redoCount = 0; 1142 int prepareCount = 0; 1143 int clrCount = 0; 1144 int btranCount = 0; 1145 int etranCount = 0; 1146 1147 1149 TransactionId tranId = null; 1150 1151 long instant = LogCounter.INVALID_LOG_INSTANT; 1153 1154 logIn.setData(logOutputBuffer.getByteArray()); 1162 1163 StreamLogScan undoScan = null; 1166 Loggable op = null; 1167 long logEnd = 0; 1169 try 1170 { 1171 1172 LogRecord record; 1174 while((record = 1175 redoScan.getNextRecord(logIn, null, 0)) 1176 != null) 1177 { 1178 scanCount++; 1179 long undoInstant = 0; 1180 1181 instant = redoScan.getInstant(); 1183 1184 logEnd = redoScan.getLogRecordEnd(); 1186 1187 1188 if (SanityManager.DEBUG) 1195 { 1196 if (SanityManager.DEBUG_ON(LogToFile.DUMP_LOG_ONLY) || 1197 SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) 1198 1199 { 1200 if (SanityManager.DEBUG_ON(LogToFile.DUMP_LOG_ONLY)) 1201 SanityManager.DEBUG_SET(LogToFile.DBG_FLAG); 1202 1203 op = record.getLoggable(); 1204 tranId = record.getTransactionId(); 1205 if (record.isCLR()) 1206 { 1207 undoInstant = logIn.readLong(); 1209 1210 SanityManager.DEBUG( 1211 LogToFile.DBG_FLAG, 1212 "scanned " + tranId + " : " + op + 1213 " instant = " + 1214 LogCounter.toDebugString(instant) + 1215 " undoInstant : " + 1216 LogCounter.toDebugString(undoInstant)); 1217 } 1218 else 1219 { 1220 SanityManager.DEBUG( 1221 LogToFile.DBG_FLAG, 1222 "scanned " + tranId + " : " + op + 1223 " instant = " + 1224 LogCounter.toDebugString(instant) 1225 + " logEnd = " + 1226 LogCounter.toDebugString(logEnd) 1227 + " logIn at " + logIn.getPosition() 1228 + " available " + logIn.available()); 1229 } 1230 1231 if (SanityManager.DEBUG_ON(LogToFile.DUMP_LOG_ONLY)) 1233 continue; 1234 } 1235 } 1236 1237 if (redoLWM != 1241 LogCounter.INVALID_LOG_INSTANT && instant < redoLWM) 1242 { 1243 if (!(record.isFirst() || 1244 record.isComplete() || 1245 record.isPrepare())) 1246 { 1247 continue; 1248 } 1249 } 1250 1251 tranId = record.getTransactionId(); 1253 1254 if (!transFactory.findTransaction(tranId, recoveryTransaction)) 1258 { 1259 1261 if (redoLWM != LogCounter.INVALID_LOG_INSTANT && 1262 instant < redoLWM && 1263 (record.isPrepare() || record.isComplete())) 1264 { 1265 etranCount++; 1282 1283 continue; 1284 } 1285 1286 if ((ttabInstant == LogCounter.INVALID_LOG_INSTANT) && 1287 !record.isFirst()) 1288 { 1289 throw StandardException.newException( 1290 SQLState.LOG_UNEXPECTED_RECOVERY_PROBLEM, 1291 MessageService.getTextMessage(MessageId.LOG_RECORD_NOT_FIRST,tranId)); 1292 1293 } 1294 1295 if (SanityManager.DEBUG) 1296 { 1297 if (ttabInstant != LogCounter.INVALID_LOG_INSTANT) 1301 { 1302 if (instant > ttabInstant && !record.isFirst()) 1303 { 1304 SanityManager.THROWASSERT( 1305 "log record is Not first but transaction " + 1306 "is not in transaction table (2) : " + tranId); 1307 } 1308 1309 } 1316 } 1317 btranCount++; 1318 1319 recoveryTransaction.setTransactionId( 1322 record.getLoggable(), tranId); 1323 1324 } 1325 else 1326 { 1327 1329 if ((ttabInstant == LogCounter.INVALID_LOG_INSTANT) && 1330 record.isFirst()) 1331 { 1332 throw StandardException.newException( 1333 SQLState.LOG_UNEXPECTED_RECOVERY_PROBLEM, 1334 MessageService.getTextMessage(MessageId.LOG_RECORD_FIRST, 1335 tranId)); 1336 1337 1338 } 1339 1340 if (SanityManager.DEBUG) 1341 { 1342 if (ttabInstant != LogCounter.INVALID_LOG_INSTANT && 1343 instant > ttabInstant && 1344 record.isFirst()) 1345 { 1346 SanityManager.THROWASSERT( 1347 "log record is first but transaction is " + 1348 "already in transaction table (3): " + tranId); 1349 } 1350 1351 if (record.isPrepare()) 1352 prepareCount++; 1353 } 1354 1355 if (record.isFirst()) 1365 { 1366 btranCount++; 1367 continue; 1368 } 1369 } 1370 1371 op = record.getLoggable(); 1372 1373 if (SanityManager.DEBUG) 1374 { 1375 if (!record.isCLR()) 1376 { 1377 if (logIn.available() < 4) 1378 { 1379 SanityManager.THROWASSERT( 1380 "not enough bytes read in : " + 1381 logIn.available() + 1382 " for " + op + " instant " + 1383 LogCounter.toDebugString(instant)); 1384 } 1385 } 1386 } 1387 1388 if (SanityManager.DEBUG) 1389 { 1390 SanityManager.ASSERT( 1391 !recoveryTransaction.handlesPostTerminationWork(), 1392 "recovery transaction handles post termination work"); 1393 } 1394 1395 if (op.needsRedo(recoveryTransaction)) 1396 { 1397 redoCount++; 1398 1399 if (record.isCLR()) 1400 { 1401 clrCount++; 1402 1403 1407 if (SanityManager.DEBUG) 1408 SanityManager.ASSERT(op instanceof Compensation); 1409 1410 1411 if (undoInstant == 0) 1413 undoInstant = logIn.readLong(); 1414 1415 if (undoScan == null) 1416 { 1417 undoScan = (StreamLogScan) 1418 logFactory.openForwardsScan( 1419 undoInstant,(LogInstant)null); 1420 } 1421 else 1422 { 1423 undoScan.resetPosition(new LogCounter(undoInstant)); 1424 } 1425 1426 1431 logIn.clearLimit(); 1434 LogRecord undoRecord = 1435 undoScan.getNextRecord(logIn, null, 0); 1436 1437 Undoable undoOp = undoRecord.getUndoable(); 1438 1439 if (SanityManager.DEBUG) 1440 { 1441 SanityManager.DEBUG( 1442 LogToFile.DBG_FLAG, 1443 "Redoing CLR: undoInstant = " + 1444 LogCounter.toDebugString(undoInstant) + 1445 " clrinstant = " + 1446 LogCounter.toDebugString(instant)); 1447 1448 SanityManager.ASSERT( 1449 undoRecord.getTransactionId().equals(tranId)); 1450 1451 SanityManager.ASSERT(undoOp != null); 1452 } 1453 1454 ((Compensation)op).setUndoOp(undoOp); 1455 } 1456 1457 1461 if (SanityManager.DEBUG) 1462 { 1463 if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) 1464 { 1465 SanityManager.DEBUG( 1466 LogToFile.DBG_FLAG, 1467 "redoing " + op + 1468 " instant = " + 1469 LogCounter.toDebugString(instant)); 1470 } 1471 } 1472 1473 int dataLength = logIn.readInt(); 1474 logIn.setLimit(logIn.getPosition(), dataLength); 1475 1476 1481 op.doMe( 1482 recoveryTransaction, 1483 new LogCounter(instant), logIn); 1484 1485 op.releaseResource(recoveryTransaction); 1486 1487 op = null; 1488 } 1489 1490 1494 if (record.isComplete()) 1502 { 1503 etranCount++; 1504 1505 if (SanityManager.DEBUG) 1506 SanityManager.ASSERT( 1507 !recoveryTransaction.handlesPostTerminationWork(), 1508 "recovery xact handles post termination work"); 1509 1510 recoveryTransaction.commit(); 1511 } 1512 } 1514 long end = redoScan.getLogRecordEnd(); 1517 if (end != LogCounter.INVALID_LOG_INSTANT 1518 && (LogCounter.getLogFileNumber(logEnd) 1519 < LogCounter.getLogFileNumber(end))) { 1520 logEnd = end; 1521 } 1522 } 1523 catch (StandardException se) 1524 { 1525 throw StandardException.newException( 1526 SQLState.LOG_REDO_FAILED, se, op); 1527 } 1528 finally 1529 { 1530 redoScan.close(); 1532 redoScan = null; 1533 1534 if (undoScan != null) 1535 { 1536 undoScan.close(); 1537 undoScan = null; 1538 } 1539 1540 if (op != null) 1541 op.releaseResource(recoveryTransaction); 1542 1543 } 1544 1545 if (SanityManager.DEBUG) 1546 { 1547 if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) 1548 { 1549 SanityManager.DEBUG( 1550 LogToFile.DBG_FLAG, 1551 "----------------------------------------------------\n" + 1552 "End of recovery redo\n" + 1553 "Scanned = " + scanCount + " log records" + 1554 ", redid = " + redoCount + 1555 " ( clr = " + clrCount + " )" + 1556 " begintran = " + btranCount + 1557 " endtran = " + etranCount + 1558 " preparetran = " + prepareCount + 1559 "\n log ends at " + LogCounter.toDebugString(logEnd) + 1560 "\n----------------------------------------------------\n"); 1561 } 1562 } 1563 1564 if (SanityManager.DEBUG) 1565 { 1566 if (instant != LogCounter.INVALID_LOG_INSTANT) 1568 { 1569 SanityManager.ASSERT( 1570 LogCounter.getLogFileNumber(instant) < 1571 LogCounter.getLogFileNumber(logEnd) || 1572 (LogCounter.getLogFileNumber(instant) == 1573 LogCounter.getLogFileNumber(logEnd) && 1574 LogCounter.getLogFilePosition(instant) <= 1575 LogCounter.getLogFilePosition(logEnd))); 1576 } 1577 else 1578 { 1579 SanityManager.ASSERT(logEnd == LogCounter.INVALID_LOG_INSTANT); 1580 } 1581 } 1582 1583 return logEnd; 1585 } 1586 1587 1588 1605 protected Loggable readLogRecord(StreamLogScan scan, int size) 1606 throws IOException , StandardException, ClassNotFoundException 1607 { 1608 Loggable lop = null; 1609 1610 ArrayInputStream logInputBuffer = new ArrayInputStream(new byte[size]); 1611 1612 LogRecord record = scan.getNextRecord(logInputBuffer, null, 0); 1613 if (record != null) 1614 lop = record.getLoggable(); 1615 return lop; 1616 } 1617 1618} 1619 | Popular Tags |