1 21 22 package org.apache.derby.impl.store.raw.log; 23 24 import org.apache.derby.iapi.reference.SQLState; 25 26 import org.apache.derby.iapi.services.io.ArrayInputStream; 27 28 import org.apache.derby.iapi.services.sanity.SanityManager; 29 30 import org.apache.derby.iapi.error.StandardException; 31 32 import org.apache.derby.iapi.store.raw.log.LogInstant; 33 34 import org.apache.derby.iapi.store.raw.xact.TransactionId; 35 36 import org.apache.derby.impl.store.raw.log.LogCounter; 37 import org.apache.derby.impl.store.raw.log.LogRecord; 38 import org.apache.derby.impl.store.raw.log.StreamLogScan; 39 40 import org.apache.derby.io.StorageRandomAccessFile; 41 42 import java.io.IOException ; 43 import org.apache.derby.iapi.store.raw.Loggable; 44 45 59 60 public class Scan implements StreamLogScan { 61 62 public static final byte FORWARD = 1; 64 public static final byte BACKWARD = 2; 65 public static final byte BACKWARD_FROM_LOG_END = 4; 66 67 private StorageRandomAccessFile scan; private LogToFile logFactory; 71 private long currentLogFileNumber; 73 private long currentLogFileLength; 77 private long knownGoodLogEnd; 87 88 private long currentInstant; 92 private long stopAt; 97 98 private byte scanDirection; 100 private boolean fuzzyLogEnd = false; 105 106 117 public Scan(LogToFile logFactory, long startAt, LogInstant stopAt, byte direction) 118 throws IOException , StandardException 119 { 120 if (SanityManager.DEBUG) 121 SanityManager.ASSERT(startAt != LogCounter.INVALID_LOG_INSTANT, 122 "cannot start scan on an invalid log instant"); 123 124 this.logFactory = logFactory; 125 currentLogFileNumber = LogCounter.getLogFileNumber(startAt); 126 currentLogFileLength = -1; 127 knownGoodLogEnd = LogCounter.INVALID_LOG_INSTANT; currentInstant = LogCounter.INVALID_LOG_INSTANT; if (stopAt != null) 130 this.stopAt = ((LogCounter) stopAt).getValueAsLong(); 131 else 132 this.stopAt = LogCounter.INVALID_LOG_INSTANT; 133 134 switch(direction) 135 { 136 case FORWARD: 137 scan = logFactory.getLogFileAtPosition(startAt); 138 scanDirection = FORWARD; 139 140 if (SanityManager.DEBUG) 141 if (scan == null) 142 SanityManager.THROWASSERT( 143 "scan null at " + LogCounter.toDebugString(startAt)); 144 145 currentLogFileLength = scan.length(); 151 break; 152 153 case BACKWARD: 154 scan = logFactory.getLogFileAtPosition(startAt); 157 int logsize = scan.readInt(); 158 159 scan.seek(scan.getFilePointer() + logsize + LogToFile.LOG_RECORD_OVERHEAD - 4); 162 scanDirection = BACKWARD; 163 break; 164 165 case BACKWARD_FROM_LOG_END: 166 scan = logFactory.getLogFileAtPosition(startAt); 168 scanDirection = BACKWARD; 169 break; 170 171 } 172 } 173 174 177 178 189 public LogRecord getNextRecord(ArrayInputStream input, 190 TransactionId tranId, 191 int groupmask) 192 throws StandardException 193 { 194 if (scan == null) 195 return null; 196 197 if (SanityManager.DEBUG) 198 SanityManager.ASSERT(scanDirection != 0, "scan has been secretly closed!"); 199 200 LogRecord lr = null; 201 try 202 { 203 if (scanDirection == BACKWARD) 204 lr = getNextRecordBackward(input, tranId, groupmask); 205 else if (scanDirection == FORWARD) 206 lr = getNextRecordForward(input, tranId, groupmask); 207 208 return lr; 209 210 } 211 catch (IOException ioe) 212 { 213 if (SanityManager.DEBUG) 214 ioe.printStackTrace(); 215 216 throw logFactory.markCorrupt( 217 StandardException.newException(SQLState.LOG_CORRUPTED, ioe)); 218 } 219 catch (ClassNotFoundException cnfe) 220 { 221 if (SanityManager.DEBUG) 222 cnfe.printStackTrace(); 223 224 throw logFactory.markCorrupt( 225 StandardException.newException(SQLState.LOG_CORRUPTED, cnfe)); 226 } 227 finally 228 { 229 if (lr == null) 230 close(); } 232 233 } 234 235 248 private LogRecord getNextRecordBackward(ArrayInputStream input, 249 TransactionId tranId, 250 int groupmask) 251 throws StandardException, IOException , ClassNotFoundException 252 { 253 if (SanityManager.DEBUG) 254 SanityManager.ASSERT(scanDirection == BACKWARD, "can only called by backward scan"); 255 256 260 boolean candidate; 261 int peekAmount = LogRecord.formatOverhead() + LogRecord.maxGroupStoredSize(); 264 if (tranId != null) 265 peekAmount += LogRecord.maxTransactionIdStoredSize(tranId); 266 267 int readAmount; 269 LogRecord lr; 270 long curpos = scan.getFilePointer(); 271 272 do 273 { 274 candidate = true; 276 lr = null; 277 readAmount = -1; 278 279 if (curpos == LogToFile.LOG_FILE_HEADER_SIZE) 280 { 281 if (stopAt != LogCounter.INVALID_LOG_INSTANT && 284 LogCounter.getLogFileNumber(stopAt) == currentLogFileNumber) 285 { 286 if (SanityManager.DEBUG) 287 { 288 if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) 289 { 290 SanityManager.DEBUG(LogToFile.DBG_FLAG, 291 "stopping at " + currentLogFileNumber); 292 } 293 } 294 295 return null; } 297 298 scan.seek(LogToFile.LOG_FILE_HEADER_PREVIOUS_LOG_INSTANT_OFFSET); 301 long previousLogInstant = scan.readLong(); 302 scan.close(); 303 304 if (SanityManager.DEBUG) 305 { 306 SanityManager.ASSERT(previousLogInstant != LogCounter.INVALID_LOG_INSTANT, 307 "scanning backward beyond the first log file"); 308 if (currentLogFileNumber != 309 LogCounter.getLogFileNumber(previousLogInstant) + 1) 310 SanityManager.THROWASSERT( 311 "scanning backward but get incorrect log file number " + 312 "expected " + (currentLogFileNumber -1) + 313 "get " + 314 LogCounter.getLogFileNumber(previousLogInstant)); 315 316 SanityManager.ASSERT(LogCounter.getLogFilePosition(previousLogInstant) > 317 LogToFile.LOG_FILE_HEADER_SIZE, 318 "scanning backward encounter completely empty log file"); 319 320 SanityManager.DEBUG(LogToFile.DBG_FLAG, 321 "scanning backwards from log file " + 322 currentLogFileNumber + ", switch to (" + 323 LogCounter.getLogFileNumber(previousLogInstant) + "," + 324 LogCounter.getLogFilePosition(previousLogInstant) + ")" 325 ); 326 } 327 328 currentLogFileNumber = LogCounter.getLogFileNumber(previousLogInstant); 330 331 scan = logFactory.getLogFileAtPosition(previousLogInstant); 332 333 curpos = scan.getFilePointer(); 339 340 if (curpos == LogToFile.LOG_FILE_HEADER_SIZE) 346 continue; 347 } 348 349 scan.seek(curpos - 4); 350 int recordLength = scan.readInt(); 352 long recordStartPosition = curpos - recordLength - 356 LogToFile.LOG_RECORD_OVERHEAD; 357 358 if (SanityManager.DEBUG) 359 { 360 if (recordStartPosition < LogToFile.LOG_FILE_HEADER_SIZE) 361 SanityManager.THROWASSERT( 362 "next position " + recordStartPosition + 363 " recordLength " + recordLength + 364 " current file position " + scan.getFilePointer()); 365 366 scan.seek(recordStartPosition); 367 368 int checkLength = scan.readInt(); 371 372 if (checkLength != recordLength) 373 { 374 long inst = LogCounter.makeLogInstantAsLong(currentLogFileNumber, recordStartPosition); 375 376 throw logFactory.markCorrupt( 377 StandardException.newException( 378 SQLState.LOG_RECORD_CORRUPTED, 379 new Long (checkLength), 380 new Long (recordLength), 381 new Long (inst), 382 new Long (currentLogFileNumber))); 383 } 384 } 385 else 386 { 387 scan.seek(recordStartPosition+4); 389 } 390 391 currentInstant = scan.readLong(); 395 396 if (SanityManager.DEBUG) 397 { 398 if (LogCounter.getLogFileNumber(currentInstant) != 400 currentLogFileNumber || 401 LogCounter.getLogFilePosition(currentInstant) != 402 recordStartPosition) 403 SanityManager.THROWASSERT( 404 "Wrong LogInstant on log record " + 405 LogCounter.toDebugString(currentInstant) + 406 " version real position (" + 407 currentLogFileNumber + "," + 408 recordStartPosition + ")"); 409 } 410 411 412 if (currentInstant < stopAt && stopAt != LogCounter.INVALID_LOG_INSTANT) 415 { 416 currentInstant = LogCounter.INVALID_LOG_INSTANT; 417 return null; } 419 420 421 byte[] data = input.getData(); 422 423 if (data.length < recordLength) 424 { 425 data = new byte[recordLength]; 428 input.setData(data); 429 } 430 431 if (logFactory.databaseEncrypted()) 434 { 435 scan.readFully(data, 0, recordLength); 436 int len = logFactory.decrypt(data, 0, recordLength, data, 0); 437 if (SanityManager.DEBUG) 438 SanityManager.ASSERT(len == recordLength); 439 input.setLimit(0, recordLength); 440 } 441 else { 443 if (groupmask == 0 && tranId == null) 444 { 445 scan.readFully(data, 0, recordLength); 447 input.setLimit(0, recordLength); 448 } 449 else 450 { 451 readAmount = (recordLength > peekAmount) ? 456 peekAmount : recordLength; 457 458 scan.readFully(data, 0, readAmount); 460 input.setLimit(0, readAmount); 461 } 462 } 463 464 lr = (LogRecord) input.readObject(); 465 466 if(lr.isChecksum()) 469 { 470 candidate = false; 471 }else if (groupmask != 0 || tranId != null) 472 { 473 474 if(lr.isChecksum()) 476 candidate = false; 477 478 if (candidate && groupmask != 0 && (groupmask & lr.group()) == 0) 479 candidate = false; 481 if (candidate && tranId != null) 482 { 483 TransactionId tid = lr.getTransactionId(); 484 if (!tid.equals(tranId)) candidate = false; } 487 488 if (candidate && !logFactory.databaseEncrypted()) 494 { 495 if (SanityManager.DEBUG) 497 SanityManager.ASSERT(readAmount > 0); 498 499 if (readAmount < recordLength) 500 { 501 int inputPosition = input.getPosition(); 506 507 scan.readFully(data, readAmount, 508 recordLength-readAmount); 509 510 input.setLimit(0, recordLength); 511 input.setPosition(inputPosition); 512 } 513 } 514 } 515 516 curpos = recordStartPosition; 520 scan.seek(curpos); 521 522 } while (candidate == false); 523 524 return lr; 525 526 } 527 528 543 private LogRecord getNextRecordForward(ArrayInputStream input, 544 TransactionId tranId, 545 int groupmask) 546 throws StandardException, IOException , ClassNotFoundException 547 { 548 if (SanityManager.DEBUG) 549 SanityManager.ASSERT(scanDirection == FORWARD, "can only called by forward scan"); 550 551 564 567 long recordStartPosition = scan.getFilePointer(); 571 572 boolean candidate; 573 574 int peekAmount = LogRecord.formatOverhead() + LogRecord.maxGroupStoredSize(); 577 if (tranId != null) 578 peekAmount += LogRecord.maxTransactionIdStoredSize(tranId); 579 580 int readAmount; 582 LogRecord lr; 583 584 do 585 { 586 candidate = true; 588 lr = null; 589 readAmount = -1; 590 591 if (recordStartPosition + 4 > currentLogFileLength) 596 { 597 if (SanityManager.DEBUG) 600 { 601 if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) 602 { 603 SanityManager.DEBUG(LogToFile.DBG_FLAG, 604 "detected fuzzy log end on log file " + 605 currentLogFileNumber + 606 " record start position " + recordStartPosition + 607 " file length " + currentLogFileLength); 608 } 609 } 610 611 if(recordStartPosition != currentLogFileLength) 615 fuzzyLogEnd = true ; 616 617 return null; 622 } 623 624 int recordLength = scan.readInt(); 626 627 while (recordLength == 0 || recordStartPosition + recordLength + 628 LogToFile.LOG_RECORD_OVERHEAD > currentLogFileLength) 629 { 630 641 if (recordLength != 0) { 643 if (SanityManager.DEBUG) 644 { 645 if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) 646 { 647 SanityManager.DEBUG( 648 LogToFile.DBG_FLAG, 649 "detected fuzzy log end on log file " + 650 currentLogFileNumber + 651 " record start position " + 652 recordStartPosition + 653 " file length " + currentLogFileLength + 654 " recordLength=" + recordLength ); 655 } 656 } 657 658 fuzzyLogEnd = true; 659 scan.close(); 660 scan = null; 661 662 return null; 663 } 664 665 667 if (SanityManager.DEBUG) 668 { 669 if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) 670 { 671 if (recordStartPosition + 4 == currentLogFileLength) 672 { 673 SanityManager.DEBUG(LogToFile.DBG_FLAG, 674 "detected proper log end on log file " + 675 currentLogFileNumber); 676 } 677 else 678 { 679 SanityManager.DEBUG(LogToFile.DBG_FLAG, 680 "detected zapped log end on log file " + 681 currentLogFileNumber + 682 " end marker at " + 683 recordStartPosition + 684 " real end at " + currentLogFileLength); 685 } 686 } 687 } 688 689 if (stopAt != LogCounter.INVALID_LOG_INSTANT && 692 LogCounter.getLogFileNumber(stopAt) == currentLogFileNumber) 693 { 694 return null; 695 } 696 697 scan.close(); 702 703 scan = logFactory.getLogFileAtBeginning(++currentLogFileNumber); 705 if (scan == null) { 707 return null; 708 } 709 710 recordStartPosition = scan.getFilePointer(); 712 713 scan.seek(LogToFile 717 .LOG_FILE_HEADER_PREVIOUS_LOG_INSTANT_OFFSET); 718 long previousLogInstant = scan.readLong(); 719 if (previousLogInstant != knownGoodLogEnd) { 720 if (SanityManager.DEBUG) { 725 if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) { 726 SanityManager.DEBUG(LogToFile.DBG_FLAG, 727 "log file " 728 + currentLogFileNumber 729 + ": previous log record: " 730 + previousLogInstant 731 + " known previous log record: " 732 + knownGoodLogEnd); 733 } 734 } 735 return null; 736 } 737 738 739 scan.seek(recordStartPosition); 740 741 if (SanityManager.DEBUG) 742 { 743 if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) 744 { 745 SanityManager.DEBUG(LogToFile.DBG_FLAG, 746 "switched to next log file " + 747 currentLogFileNumber); 748 } 749 } 750 751 knownGoodLogEnd = LogCounter.makeLogInstantAsLong 755 (currentLogFileNumber, recordStartPosition); 756 757 currentLogFileLength = scan.length(); 759 760 if (recordStartPosition+4 >= currentLogFileLength) { 762 if (SanityManager.DEBUG) 763 { 764 if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) 765 { 766 SanityManager.DEBUG(LogToFile.DBG_FLAG, 767 "log file " + currentLogFileNumber + 768 " is empty"); 769 } 770 } 771 772 return null; 773 } 774 775 recordLength = scan.readInt(); 779 } 780 781 783 currentInstant = scan.readLong(); 785 786 797 if(currentInstant < knownGoodLogEnd) 798 { 799 fuzzyLogEnd = true ; 800 return null; 801 } 802 803 if (SanityManager.DEBUG) 805 { 806 if (LogCounter.getLogFileNumber(currentInstant) != 807 currentLogFileNumber || 808 LogCounter.getLogFilePosition(currentInstant) != 809 recordStartPosition) 810 SanityManager.THROWASSERT( 811 "Wrong LogInstant on log record " + 812 LogCounter.toDebugString(currentInstant) + 813 " version real position (" + 814 currentLogFileNumber + "," + 815 recordStartPosition + ")"); 816 } 817 818 819 if (stopAt != LogCounter.INVALID_LOG_INSTANT && currentInstant > stopAt) 822 { 823 currentInstant = LogCounter.INVALID_LOG_INSTANT; 824 return null; } 826 827 byte[] data = input.getData(); 829 830 if (data.length < recordLength) 831 { 832 data = new byte[recordLength]; 835 input.setData(data); 836 } 837 838 841 if (logFactory.databaseEncrypted()) 842 { 843 scan.readFully(data, 0, recordLength); 844 int len = logFactory.decrypt(data, 0, recordLength, data, 0); 845 if (SanityManager.DEBUG) 846 SanityManager.ASSERT(len == recordLength); 847 848 input.setLimit(0, len); 849 } 850 else { 852 if (groupmask == 0 && tranId == null) 853 { 854 scan.readFully(data, 0, recordLength); 856 input.setLimit(0, recordLength); 857 } 858 else 859 { 860 readAmount = (recordLength > peekAmount) ? 865 peekAmount : recordLength; 866 867 scan.readFully(data, 0, readAmount); 869 input.setLimit(0, readAmount); 870 } 871 } 872 873 lr = (LogRecord) input.readObject(); 874 if (groupmask != 0 || tranId != null) 875 { 876 if (groupmask != 0 && (groupmask & lr.group()) == 0) 877 candidate = false; 879 if (candidate && tranId != null) 880 { 881 TransactionId tid = lr.getTransactionId(); 882 if (!tid.equals(tranId)) candidate = false; } 885 886 if (candidate && !logFactory.databaseEncrypted()) 892 { 893 if (SanityManager.DEBUG) 895 SanityManager.ASSERT(readAmount > 0); 896 897 if (readAmount < recordLength) 898 { 899 int inputPosition = input.getPosition(); 904 905 scan.readFully(data, readAmount, 906 recordLength-readAmount); 907 908 input.setLimit(0, recordLength); 909 input.setPosition(inputPosition); 910 } 911 } 912 } 913 914 928 if (!candidate) 932 scan.seek(recordStartPosition - 4); 933 int checkLength = scan.readInt(); 934 if (checkLength != recordLength && checkLength < recordLength) 935 { 936 937 938 if(checkLength < recordLength) 942 { 943 fuzzyLogEnd = true ; 944 return null; 945 }else 946 { 947 948 953 if (SanityManager.DEBUG) 954 { 955 throw logFactory.markCorrupt 956 (StandardException.newException( 957 SQLState.LOG_RECORD_CORRUPTED, 958 new Long (checkLength), 959 new Long (recordLength), 960 new Long (currentInstant), 961 new Long (currentLogFileNumber))); 962 963 } 964 965 } 968 969 } 970 971 recordStartPosition += recordLength + LogToFile.LOG_RECORD_OVERHEAD; 973 knownGoodLogEnd = LogCounter.makeLogInstantAsLong 974 (currentLogFileNumber, recordStartPosition); 975 976 977 if (SanityManager.DEBUG) 978 { 979 if (recordStartPosition != scan.getFilePointer()) 980 SanityManager.THROWASSERT( 981 "calculated end " + recordStartPosition + 982 " != real end " + scan.getFilePointer()); 983 } 984 else 985 { 986 scan.seek(recordStartPosition); 988 } 989 990 993 994 1001 if(lr.isChecksum()) 1002 { 1003 1006 candidate = false; 1007 Loggable op = lr.getLoggable(); 1008 if (SanityManager.DEBUG) 1009 { 1010 if (SanityManager.DEBUG_ON(LogToFile.DUMP_LOG_ONLY) || 1011 SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) 1012 1013 SanityManager.DEBUG(LogToFile.DBG_FLAG, 1014 "scanned " + "Null" + " : " + op + 1015 " instant = " + 1016 LogCounter.toDebugString(currentInstant) + 1017 " logEnd = " + LogCounter.toDebugString(knownGoodLogEnd)); 1018 } 1019 1020 ChecksumOperation clop = (ChecksumOperation) op; 1021 int ckDataLength = clop.getDataLength(); 1022 if (data.length < ckDataLength) 1024 { 1025 data = new byte[ckDataLength]; 1028 input.setData(data); 1029 input.setLimit(0, ckDataLength); 1030 } 1031 1032 boolean validChecksum = false; 1033 if((recordStartPosition + ckDataLength) <= currentLogFileLength) 1037 { 1038 scan.readFully(data, 0, ckDataLength); 1040 if(clop.isChecksumValid(data, 0 , ckDataLength)) 1042 validChecksum = true; 1043 } 1044 1045 1046 if(!validChecksum) 1047 { 1048 1053 if (SanityManager.DEBUG) 1054 { 1055 if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) 1056 { 1057 SanityManager.DEBUG( 1058 LogToFile.DBG_FLAG, 1059 "detected fuzzy log end on log file while doing checksum checks " + 1060 currentLogFileNumber + 1061 " checksum record start position " + recordStartPosition + 1062 " file length " + currentLogFileLength + 1063 " checksumDataLength=" + ckDataLength); 1064 } 1065 1066 } 1067 1068 fuzzyLogEnd = true; 1069 scan.close(); 1070 scan = null; 1071 return null; 1072 } 1073 1074 scan.seek(recordStartPosition); 1076 } 1077 1078 1079 } while (candidate == false) ; 1080 1081 return lr; 1082 } 1083 1084 1085 1092 1093 public void resetPosition(LogInstant instant) 1094 throws IOException , StandardException 1095 { 1096 if (SanityManager.DEBUG) 1097 SanityManager.ASSERT(instant != null); 1098 1099 long instant_long = ((LogCounter)instant).getValueAsLong(); 1100 1101 if ((instant_long == LogCounter.INVALID_LOG_INSTANT) || 1102 (stopAt != LogCounter.INVALID_LOG_INSTANT && 1103 (scanDirection == FORWARD && instant_long > stopAt) || 1104 (scanDirection == FORWARD && instant_long < stopAt))) 1105 { 1106 close(); 1107 1108 throw StandardException.newException( 1109 SQLState.LOG_RESET_BEYOND_SCAN_LIMIT, 1110 instant, new LogCounter(stopAt)); 1111 } 1112 else 1113 { 1114 long fnum = ((LogCounter)instant).getLogFileNumber(); 1115 1116 if (fnum != currentLogFileNumber) 1117 { 1118 if (SanityManager.DEBUG) 1119 { 1120 if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) 1121 { 1122 SanityManager.DEBUG(LogToFile.DBG_FLAG, 1123 "Scan " + scanDirection + 1124 " resetting to " + instant + 1125 " need to switch log from " + 1126 currentLogFileNumber + " to " + fnum); 1127 } 1128 } 1129 1130 scan.close(); 1131 scan = logFactory.getLogFileAtPosition(instant_long); 1132 1133 currentLogFileNumber= fnum; 1134 1135 if (scanDirection == FORWARD) 1136 { 1137 currentLogFileLength = scan.length(); 1146 } 1147 } 1148 else 1149 1150 { 1151 long fpos = ((LogCounter)instant).getLogFilePosition(); 1152 scan.seek(fpos); 1153 1154 currentLogFileLength = scan.length(); 1157 1158 if (SanityManager.DEBUG) 1159 { 1160 if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) 1161 { 1162 SanityManager.DEBUG(LogToFile.DBG_FLAG, 1163 "Scan reset to " + instant); 1164 } 1165 } 1166 } 1167 1168 1169 currentInstant = instant_long; 1170 1171 knownGoodLogEnd = currentInstant; 1179 1180 if (SanityManager.DEBUG) 1181 { 1182 if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) 1183 { 1184 SanityManager.DEBUG(LogToFile.DBG_FLAG, 1185 "Scan.getInstant reset to " + currentInstant + 1186 LogCounter.toDebugString(currentInstant)); 1187 } 1188 } 1189 } 1190 } 1191 1192 1196 public long getInstant() 1197 { 1198 return currentInstant; 1199 } 1200 1201 1210 public long getLogRecordEnd() 1211 { 1212 return knownGoodLogEnd; 1213 } 1214 1215 1220 public boolean isLogEndFuzzy() 1221 { 1222 return fuzzyLogEnd; 1223 } 1224 1225 1229 public LogInstant getLogInstant() 1230 { 1231 if (currentInstant == LogCounter.INVALID_LOG_INSTANT) 1232 return null; 1233 else 1234 return new LogCounter(currentInstant); 1235 } 1236 1237 1240 public void close() 1241 { 1242 if (scan != null) 1243 { 1244 try 1245 { 1246 scan.close(); 1247 } 1248 catch (IOException ioe) 1249 {} 1250 1251 scan = null; 1252 } 1253 1254 logFactory = null; 1255 currentLogFileNumber = -1; 1256 currentLogFileLength = -1; 1257 currentInstant = LogCounter.INVALID_LOG_INSTANT; 1260 stopAt = LogCounter.INVALID_LOG_INSTANT; 1261 scanDirection = 0; 1262 } 1263 1264} 1265 | Popular Tags |