1 8 9 package com.sleepycat.je.recovery; 10 11 import java.io.IOException ; 12 import java.util.ArrayList ; 13 import java.util.HashMap ; 14 import java.util.HashSet ; 15 import java.util.Iterator ; 16 import java.util.List ; 17 import java.util.Map ; 18 import java.util.Set ; 19 import java.util.logging.Level ; 20 import java.util.logging.Logger ; 21 22 import com.sleepycat.je.CheckpointConfig; 23 import com.sleepycat.je.DatabaseException; 24 import com.sleepycat.je.DbInternal; 25 import com.sleepycat.je.TransactionConfig; 26 import com.sleepycat.je.cleaner.UtilizationTracker; 27 import com.sleepycat.je.config.EnvironmentParams; 28 import com.sleepycat.je.dbi.DatabaseId; 29 import com.sleepycat.je.dbi.DatabaseImpl; 30 import com.sleepycat.je.dbi.DbConfigManager; 31 import com.sleepycat.je.dbi.DbTree; 32 import com.sleepycat.je.dbi.EnvironmentImpl; 33 import com.sleepycat.je.latch.LatchSupport; 34 import com.sleepycat.je.log.CheckpointFileReader; 35 import com.sleepycat.je.log.FileManager; 36 import com.sleepycat.je.log.INFileReader; 37 import com.sleepycat.je.log.LNFileReader; 38 import com.sleepycat.je.log.LastFileReader; 39 import com.sleepycat.je.log.LogEntryType; 40 import com.sleepycat.je.log.LogFileNotFoundException; 41 import com.sleepycat.je.tree.BIN; 42 import com.sleepycat.je.tree.ChildReference; 43 import com.sleepycat.je.tree.DIN; 44 import com.sleepycat.je.tree.IN; 45 import com.sleepycat.je.tree.Key; 46 import com.sleepycat.je.tree.LN; 47 import com.sleepycat.je.tree.Node; 48 import com.sleepycat.je.tree.SearchResult; 49 import com.sleepycat.je.tree.TrackingInfo; 50 import com.sleepycat.je.tree.Tree; 51 import com.sleepycat.je.tree.TreeLocation; 52 import com.sleepycat.je.tree.WithRootLatched; 53 import com.sleepycat.je.txn.LockType; 54 import com.sleepycat.je.txn.Txn; 55 import com.sleepycat.je.utilint.DbLsn; 56 import com.sleepycat.je.utilint.Tracer; 57 58 public class RecoveryManager { 59 private static final String TRACE_DUP_ROOT_REPLACE = 60 "DupRootRecover:"; 61 private static final String TRACE_LN_REDO = "LNRedo:"; 62 private static final String TRACE_LN_UNDO = "LNUndo"; 63 private static final String TRACE_IN_REPLACE = "INRecover:"; 64 private static final String TRACE_ROOT_REPLACE = "RootRecover:"; 65 private static final String TRACE_IN_DEL_REPLAY = "INDelReplay:"; 66 private static final String TRACE_IN_DUPDEL_REPLAY = "INDupDelReplay:"; 67 private static final String TRACE_ROOT_DELETE = "RootDelete:"; 68 69 private static final int CLEAR_INCREMENT = 50; 70 71 private EnvironmentImpl env; 72 private int readBufferSize; 73 private RecoveryInfo info; private Set committedTxnIds; private Set abortedTxnIds; private Map preparedTxns; private Set inListRebuildDbIds; 80 private Level detailedTraceLevel; private Map fileSummaryLsns; private int inListClearCounter; 84 87 public RecoveryManager(EnvironmentImpl env) 88 throws DatabaseException { 89 90 this.env = env; 91 DbConfigManager cm = env.getConfigManager(); 92 readBufferSize = 93 cm.getInt(EnvironmentParams.LOG_ITERATOR_READ_SIZE); 94 committedTxnIds = new HashSet (); 95 abortedTxnIds = new HashSet (); 96 preparedTxns = new HashMap (); 97 inListRebuildDbIds = new HashSet (); 98 fileSummaryLsns = new HashMap (); 99 100 105 detailedTraceLevel = 106 Tracer.parseLevel(env, 107 EnvironmentParams.JE_LOGGING_LEVEL_RECOVERY); 108 } 109 110 116 public RecoveryInfo recover(boolean readOnly) 117 throws DatabaseException { 118 119 info = new RecoveryInfo(); 120 121 try { 122 FileManager fileManager = env.getFileManager(); 123 DbConfigManager configManager = env.getConfigManager(); 124 boolean forceCheckpoint = 125 configManager.getBoolean 126 (EnvironmentParams.ENV_RECOVERY_FORCE_CHECKPOINT); 127 if (fileManager.filesExist()) { 128 129 134 findEndOfLog(readOnly); 135 Tracer.trace(Level.CONFIG, env, 136 "Recovery underway, found end of log"); 137 138 142 findLastCheckpoint(); 143 env.getLogManager().setLastLsnAtRecovery 144 (fileManager.getLastUsedLsn()); 145 Tracer.trace(Level.CONFIG, env, 146 "Recovery checkpoint search, " + 147 info); 148 149 150 env.readMapTreeFromLog(info.useRootLsn); 151 152 153 buildTree(); 154 } else { 155 156 160 env.enableDebugLoggingToDbLog(); 161 Tracer.trace(Level.CONFIG, env, "Recovery w/no files."); 162 env.logMapTreeRoot(); 163 164 167 forceCheckpoint = true; 168 } 169 170 if (preparedTxns.size() > 0) { 171 Tracer.trace(Level.INFO, env, 172 "There are " + preparedTxns.size() + 173 " prepared but unfinished txns."); 174 175 179 preparedTxns = null; 180 } 181 182 187 if (DbInternal.getCreateUP 188 (env.getConfigManager().getEnvironmentConfig())) { 189 env.getUtilizationProfile().populateCache(); 190 } 191 192 215 if (!readOnly && 216 (env.getLogManager().getLastLsnAtRecovery() != 217 info.checkpointEndLsn || 218 forceCheckpoint)) { 219 CheckpointConfig config = new CheckpointConfig(); 220 config.setForce(true); 221 config.setMinimizeRecoveryTime(true); 222 env.invokeCheckpoint 223 (config, 224 false, "recovery"); 226 } else { 227 228 env.getCheckpointer().initIntervals 229 (info.checkpointEndLsn, System.currentTimeMillis()); 230 } 231 232 } catch (IOException e) { 233 Tracer.trace(env, "RecoveryManager", "recover", 234 "Couldn't recover", e); 235 throw new RecoveryException(env, "Couldn't recover: " + 236 e.getMessage(), e); 237 } finally { 238 Tracer.trace(Level.CONFIG, env, "Recovery finished: " + info); 239 } 240 241 return info; 242 } 243 244 248 private void findEndOfLog(boolean readOnly) 249 throws IOException , DatabaseException { 250 251 LastFileReader reader = new LastFileReader(env, readBufferSize); 252 253 259 while (reader.readNextEntry()) { 260 LogEntryType type = reader.getEntryType(); 261 if (LogEntryType.LOG_CKPT_END.equals(type)) { 262 info.checkpointEndLsn = reader.getLastLsn(); 263 info.partialCheckpointStartLsn = DbLsn.NULL_LSN; 264 } else if (LogEntryType.LOG_CKPT_START.equals(type)) { 265 if (info.partialCheckpointStartLsn == DbLsn.NULL_LSN) { 266 info.partialCheckpointStartLsn = reader.getLastLsn(); 267 } 268 } 269 } 270 271 276 assert (reader.getLastValidLsn() != reader.getEndOfLog()): 277 "lastUsed=" + DbLsn.getNoFormatString(reader.getLastValidLsn()) + 278 " end=" + DbLsn.getNoFormatString(reader.getEndOfLog()); 279 280 281 282 if (!readOnly) { 283 reader.setEndOfFile(); 284 } 285 286 287 info.lastUsedLsn = reader.getLastValidLsn(); 288 info.nextAvailableLsn = reader.getEndOfLog(); 289 info.nRepeatIteratorReads += reader.getNRepeatIteratorReads(); 290 env.getFileManager().setLastPosition(info.nextAvailableLsn, 291 info.lastUsedLsn, 292 reader.getPrevOffset()); 293 294 299 env.enableDebugLoggingToDbLog(); 300 } 301 302 306 private void findLastCheckpoint() 307 throws IOException , DatabaseException { 308 309 315 if (info.checkpointEndLsn == DbLsn.NULL_LSN) { 316 317 321 CheckpointFileReader searcher = 322 new CheckpointFileReader(env, readBufferSize, false, 323 info.lastUsedLsn, DbLsn.NULL_LSN, 324 info.nextAvailableLsn); 325 326 while (searcher.readNextEntry()) { 327 328 333 if (searcher.isCheckpointEnd()) { 334 335 339 info.checkpointEndLsn = searcher.getLastLsn(); 340 break; 341 } else if (searcher.isCheckpointStart()) { 342 343 346 info.partialCheckpointStartLsn = searcher.getLastLsn(); 347 348 } else if (searcher.isRoot()) { 349 350 354 if (info.useRootLsn == DbLsn.NULL_LSN) { 355 info.useRootLsn = searcher.getLastLsn(); 356 } 357 } 358 } 359 info.nRepeatIteratorReads += searcher.getNRepeatIteratorReads(); 360 } 361 362 366 if (info.checkpointEndLsn == DbLsn.NULL_LSN) { 367 info.checkpointStartLsn = DbLsn.NULL_LSN; 368 info.firstActiveLsn = DbLsn.NULL_LSN; 369 } else { 370 371 CheckpointEnd checkpointEnd = 372 (CheckpointEnd) (env.getLogManager().get 373 (info.checkpointEndLsn)); 374 info.checkpointEnd = checkpointEnd; 375 info.checkpointStartLsn = checkpointEnd.getCheckpointStartLsn(); 376 info.firstActiveLsn = checkpointEnd.getFirstActiveLsn(); 377 if (checkpointEnd.getRootLsn() != DbLsn.NULL_LSN) { 378 info.useRootLsn = checkpointEnd.getRootLsn(); 379 } 380 381 382 env.getCheckpointer().setCheckpointId(checkpointEnd.getId()); 383 env.getCheckpointer().setFirstActiveLsn 384 (checkpointEnd.getFirstActiveLsn()); 385 } 386 if (info.useRootLsn == DbLsn.NULL_LSN) { 387 throw new NoRootException 388 (env, 389 "This environment's log file has no root. Since the root " + 390 "is the first entry written into a log at environment " + 391 "creation, this should only happen if the initial creation " + 392 "of the environment was never checkpointed or synced. " + 393 "Please move aside the existing log files to allow the " + 394 "creation of a new environment"); 395 } 396 } 397 398 401 private void buildTree() 402 throws IOException , DatabaseException { 403 404 inListClearCounter = 0; 405 406 411 int passNum = buildINs(1, 412 true, 413 false); 414 415 416 420 Tracer.trace(Level.CONFIG, env, passStartHeader(passNum) + 421 "undo map LNs"); 422 long start = System.currentTimeMillis(); 423 Set mapLNSet = new HashSet (); 424 mapLNSet.add(LogEntryType.LOG_MAPLN_TRANSACTIONAL); 425 mapLNSet.add(LogEntryType.LOG_TXN_COMMIT); 426 mapLNSet.add(LogEntryType.LOG_TXN_ABORT); 427 mapLNSet.add(LogEntryType.LOG_TXN_PREPARE); 428 undoLNs(info, mapLNSet); 429 long end = System.currentTimeMillis(); 430 Tracer.trace(Level.CONFIG, env, passEndHeader(passNum, start, end) + 431 info.toString()); 432 passNum++; 433 434 438 Tracer.trace(Level.CONFIG, env, passStartHeader(passNum) + 439 "redo map LNs"); 440 start = System.currentTimeMillis(); 441 mapLNSet.add(LogEntryType.LOG_MAPLN); 442 redoLNs(info, mapLNSet); 443 end = System.currentTimeMillis(); 444 Tracer.trace(Level.CONFIG, env, passEndHeader(passNum, start, end) + 445 info.toString()); 446 passNum++; 447 448 451 passNum = buildINs(passNum, 452 false, 453 false); 454 455 458 passNum = buildINs(passNum, 459 false, 460 true); 461 462 467 rebuildINList(); 468 env.invokeEvictor(); 469 470 474 Tracer.trace(Level.CONFIG, env, passStartHeader(9) + "undo LNs"); 475 start = System.currentTimeMillis(); 476 Set lnSet = new HashSet (); 477 lnSet.add(LogEntryType.LOG_LN_TRANSACTIONAL); 478 lnSet.add(LogEntryType.LOG_NAMELN_TRANSACTIONAL); 479 lnSet.add(LogEntryType.LOG_DEL_DUPLN_TRANSACTIONAL); 480 lnSet.add(LogEntryType.LOG_DUPCOUNTLN_TRANSACTIONAL); 481 482 undoLNs(info, lnSet); 483 end = System.currentTimeMillis(); 484 Tracer.trace(Level.CONFIG, env, passEndHeader(9, start, end) + 485 info.toString()); 486 487 488 Tracer.trace(Level.CONFIG, env, passStartHeader(10) + "redo LNs"); 489 start = System.currentTimeMillis(); 490 lnSet.add(LogEntryType.LOG_LN); 491 lnSet.add(LogEntryType.LOG_NAMELN); 492 lnSet.add(LogEntryType.LOG_DEL_DUPLN); 493 lnSet.add(LogEntryType.LOG_DUPCOUNTLN); 494 lnSet.add(LogEntryType.LOG_FILESUMMARYLN); 495 redoLNs(info, lnSet); 496 end = System.currentTimeMillis(); 497 Tracer.trace(Level.CONFIG, env, passEndHeader(10, start, end) + 498 info.toString()); 499 } 500 501 506 private int buildINs(int passNum, 507 boolean mappingTree, 508 boolean dupTree) 509 throws IOException , DatabaseException { 510 511 Set targetEntries = new HashSet (); 512 Set deltaType = new HashSet (); 513 String passADesc = null; 514 String passBDesc = null; 515 String passCDesc = null; 516 517 if (mappingTree) { 518 passADesc = "read mapping INs"; 519 passBDesc = "redo mapping INs"; 520 passCDesc = "read mapping BINDeltas"; 521 } else if (dupTree) { 522 passADesc = "read dup INs"; 523 passBDesc = "redo dup INs"; 524 passCDesc = "read dup BINDeltas"; 525 } else { 526 passADesc = "read main INs"; 527 passBDesc = "redo main INs"; 528 passCDesc = "read main BINDeltas"; 529 } 530 531 if (dupTree) { 532 533 targetEntries.add(LogEntryType.LOG_DIN); 534 targetEntries.add(LogEntryType.LOG_DBIN); 535 targetEntries.add(LogEntryType.LOG_IN_DUPDELETE_INFO); 536 deltaType.add(LogEntryType.LOG_DUP_BIN_DELTA); 537 } else { 538 539 targetEntries.add(LogEntryType.LOG_IN); 540 targetEntries.add(LogEntryType.LOG_BIN); 541 targetEntries.add(LogEntryType.LOG_IN_DELETE_INFO); 542 deltaType.add(LogEntryType.LOG_BIN_DELTA); 543 } 544 545 548 Tracer.trace(Level.CONFIG, env, passStartHeader(passNum) + passADesc); 549 LevelRecorder recorder = new LevelRecorder(); 550 long start = System.currentTimeMillis(); 551 if (mappingTree) { 552 readINsAndTrackIds(info.checkpointStartLsn, recorder); 553 } else { 554 int numINsSeen = readINs(info.checkpointStartLsn, 555 false, targetEntries, 557 562 (dupTree? true: false), 563 recorder); 564 if (dupTree) { 565 info.numDuplicateINs += numINsSeen; 566 } else { 567 info.numOtherINs += numINsSeen; 568 } 569 } 570 long end = System.currentTimeMillis(); 571 Tracer.trace(Level.CONFIG, env, passEndHeader(passNum, start, end) + 572 info.toString()); 573 passNum++; 574 575 579 Set redoSet = recorder.getDbsWithDifferentLevels(); 580 if (redoSet.size() > 0) { 581 Tracer.trace(Level.CONFIG, env, 582 passStartHeader(passNum) + passBDesc); 583 start = System.currentTimeMillis(); 584 repeatReadINs(info.checkpointStartLsn, 585 targetEntries, 586 redoSet); 587 end = System.currentTimeMillis(); 588 Tracer.trace(Level.CONFIG, env, 589 passEndHeader(passNum, start, end) + info.toString()); 590 passNum++; 591 } 592 593 603 Tracer.trace(Level.CONFIG, env, passStartHeader(passNum) + passCDesc); 604 start = System.currentTimeMillis(); 605 info.numBinDeltas += readINs(info.checkpointStartLsn, 606 mappingTree, 607 deltaType, 608 true, null); end = System.currentTimeMillis(); 611 Tracer.trace(Level.CONFIG, env, 612 passEndHeader(passNum, start, end) + info.toString()); 613 passNum++; 614 615 return passNum; 616 } 617 618 622 private void readINsAndTrackIds(long rollForwardLsn, 623 LevelRecorder recorder) 624 throws IOException , DatabaseException { 625 626 INFileReader reader = 627 new INFileReader(env, 628 readBufferSize, 629 rollForwardLsn, info.nextAvailableLsn, true, false, info.partialCheckpointStartLsn, 634 fileSummaryLsns); 635 reader.addTargetType(LogEntryType.LOG_IN); 636 reader.addTargetType(LogEntryType.LOG_BIN); 637 reader.addTargetType(LogEntryType.LOG_IN_DELETE_INFO); 638 639 640 reader.setAlwaysValidateChecksum(true); 641 642 try { 643 info.numMapINs = 0; 644 DbTree dbMapTree = env.getDbMapTree(); 645 646 650 while (reader.readNextEntry()) { 651 DatabaseId dbId = reader.getDatabaseId(); 652 if (dbId.equals(DbTree.ID_DB_ID)) { 653 DatabaseImpl db = dbMapTree.getDb(dbId); 654 replayOneIN(reader, db, false, recorder); 655 info.numMapINs++; 656 } 657 } 658 659 663 info.useMaxNodeId = reader.getMaxNodeId(); 664 info.useMaxDbId = reader.getMaxDbId(); 665 info.useMaxTxnId = reader.getMaxTxnId(); 666 if (info.checkpointEnd != null) { 667 if (info.useMaxNodeId < info.checkpointEnd.getLastNodeId()) { 668 info.useMaxNodeId = info.checkpointEnd.getLastNodeId(); 669 } 670 if (info.useMaxDbId < info.checkpointEnd.getLastDbId()) { 671 info.useMaxDbId = info.checkpointEnd.getLastDbId(); 672 } 673 if (info.useMaxTxnId < info.checkpointEnd.getLastTxnId()) { 674 info.useMaxTxnId = info.checkpointEnd.getLastTxnId(); 675 } 676 } 677 678 Node.setLastNodeId(info.useMaxNodeId); 679 env.getDbMapTree().setLastDbId(info.useMaxDbId); 680 env.getTxnManager().setLastTxnId(info.useMaxTxnId); 681 682 info.nRepeatIteratorReads += reader.getNRepeatIteratorReads(); 683 } catch (Exception e) { 684 traceAndThrowException(reader.getLastLsn(), "readMapIns", e); 685 } 686 } 687 688 691 private int readINs(long rollForwardLsn, 692 boolean mapDbOnly, 693 Set targetLogEntryTypes, 694 boolean requireExactMatch, 695 LevelRecorder recorder) 696 throws IOException , DatabaseException { 697 698 INFileReader reader = 700 new INFileReader(env, 701 readBufferSize, 702 rollForwardLsn, info.nextAvailableLsn, false, 705 mapDbOnly, 706 info.partialCheckpointStartLsn, 707 fileSummaryLsns); 708 709 Iterator iter = targetLogEntryTypes.iterator(); 710 while (iter.hasNext()) { 711 reader.addTargetType((LogEntryType) iter.next()); 712 } 713 714 int numINsSeen = 0; 715 try { 716 717 721 DbTree dbMapTree = env.getDbMapTree(); 722 while (reader.readNextEntry()) { 723 DatabaseId dbId = reader.getDatabaseId(); 724 boolean isMapDb = dbId.equals(DbTree.ID_DB_ID); 725 boolean isTarget = false; 726 727 if (mapDbOnly && isMapDb) { 728 isTarget = true; 729 } else if (!mapDbOnly && !isMapDb) { 730 isTarget = true; 731 } 732 if (isTarget) { 733 DatabaseImpl db = dbMapTree.getDb(dbId); 734 if (db == null) { 735 } else { 737 replayOneIN(reader, db, requireExactMatch, recorder); 738 numINsSeen++; 739 740 745 inListRebuildDbIds.add(dbId); 746 } 747 } 748 } 749 750 info.nRepeatIteratorReads += reader.getNRepeatIteratorReads(); 751 return numINsSeen; 752 } catch (Exception e) { 753 traceAndThrowException(reader.getLastLsn(), "readNonMapIns", e); 754 return 0; 755 } 756 } 757 758 761 private void repeatReadINs(long rollForwardLsn, 762 Set targetLogEntryTypes, 763 Set targetDbs) 764 throws IOException , DatabaseException { 765 766 INFileReader reader = 768 new INFileReader(env, 769 readBufferSize, 770 rollForwardLsn, info.nextAvailableLsn, false, 773 false, info.partialCheckpointStartLsn, 775 fileSummaryLsns); 776 777 Iterator iter = targetLogEntryTypes.iterator(); 778 while (iter.hasNext()) { 779 reader.addTargetType((LogEntryType) iter.next()); 780 } 781 782 try { 783 784 785 DbTree dbMapTree = env.getDbMapTree(); 786 while (reader.readNextEntry()) { 787 DatabaseId dbId = reader.getDatabaseId(); 788 if (targetDbs.contains(dbId)) { 789 DatabaseImpl db = dbMapTree.getDb(dbId); 790 if (db == null) { 791 } else { 793 replayOneIN(reader, 794 db, 795 true, null); } 798 } 799 } 800 801 info.nRepeatIteratorReads += reader.getNRepeatIteratorReads(); 802 } catch (Exception e) { 803 traceAndThrowException(reader.getLastLsn(), "readNonMapIns", e); 804 } 805 } 806 807 810 private void replayOneIN(INFileReader reader, 811 DatabaseImpl db, 812 boolean requireExactMatch, 813 LevelRecorder recorder) 814 throws DatabaseException { 815 816 if (reader.isDeleteInfo()) { 817 818 replayINDelete(db, 819 reader.getDeletedNodeId(), 820 false, 821 reader.getDeletedIdKey(), 822 null, 823 reader.getLastLsn()); 824 } else if (reader.isDupDeleteInfo()) { 825 826 replayINDelete(db, 827 reader.getDupDeletedNodeId(), 828 true, 829 reader.getDupDeletedMainKey(), 830 reader.getDupDeletedDupKey(), 831 reader.getLastLsn()); 832 } else { 833 834 845 IN in = reader.getIN(); 846 long inLsn = reader.getLsnOfIN(); 847 in.postRecoveryInit(db, inLsn); 848 in.latch(); 849 850 854 if (recorder != null) { 855 recorder.record(db.getId(), in.getLevel()); 856 } 857 replaceOrInsert(db, in, reader.getLastLsn(), inLsn, 858 requireExactMatch); 859 } 860 861 874 if ((++inListClearCounter % CLEAR_INCREMENT) == 0) { 875 env.getInMemoryINs().clear(); 876 } 877 } 878 879 884 private void undoLNs(RecoveryInfo info, Set lnTypes) 885 throws IOException , DatabaseException { 886 887 long firstActiveLsn = info.firstActiveLsn; 888 long lastUsedLsn = info.lastUsedLsn; 889 long endOfFileLsn = info.nextAvailableLsn; 890 891 LNFileReader reader = 892 new LNFileReader(env, readBufferSize, lastUsedLsn, 893 false, endOfFileLsn, firstActiveLsn, null); 894 895 Iterator iter = lnTypes.iterator(); 896 while (iter.hasNext()) { 897 LogEntryType lnType = (LogEntryType) iter.next(); 898 reader.addTargetType(lnType); 899 } 900 901 Map countedFileSummaries = new HashMap (); Set countedAbortLsnNodes = new HashSet (); 904 DbTree dbMapTree = env.getDbMapTree(); 905 TreeLocation location = new TreeLocation(); 906 try { 907 908 912 while (reader.readNextEntry()) { 913 if (reader.isLN()) { 914 915 916 Long txnId = reader.getTxnId(); 917 918 922 if (txnId != null && 923 !committedTxnIds.contains(txnId)) { 924 925 928 env.invokeEvictor(); 929 930 LN ln = reader.getLN(); 931 long logLsn = reader.getLastLsn(); 932 long abortLsn = reader.getAbortLsn(); 933 boolean abortKnownDeleted = 934 reader.getAbortKnownDeleted(); 935 DatabaseId dbId = reader.getDatabaseId(); 936 DatabaseImpl db = dbMapTree.getDb(dbId); 937 938 939 if (db != null) { 940 ln.postFetchInit(db, logLsn); 941 try { 942 undo(detailedTraceLevel, 943 db, 944 location, 945 ln, 946 reader.getKey(), 947 reader.getDupTreeKey(), 948 logLsn, 949 abortLsn, 950 abortKnownDeleted, 951 info, 952 true); 953 } finally { 954 if (location.bin != null) { 955 location.bin.releaseLatchIfOwner(); 956 } 957 } 958 959 TxnNodeId txnNodeId = 960 new TxnNodeId(reader.getNodeId(), 961 txnId.longValue()); 962 undoUtilizationInfo(ln, logLsn, abortLsn, 963 abortKnownDeleted, 964 reader.getLastEntrySize(), 965 txnNodeId, 966 countedFileSummaries, 967 countedAbortLsnNodes); 968 969 975 inListRebuildDbIds.add(dbId); 976 } 977 } 978 } else if (reader.isPrepare()) { 979 980 985 long prepareId = reader.getTxnPrepareId(); 986 Long prepareIdL = new Long (prepareId); 987 if (!committedTxnIds.contains(prepareIdL) && 988 !abortedTxnIds.contains(prepareIdL)) { 989 TransactionConfig txnConf = new TransactionConfig(); 990 Txn preparedTxn = new Txn(env, txnConf, prepareId); 991 preparedTxn.setLockTimeout(0); 992 preparedTxns.put(prepareIdL, preparedTxn); 993 env.getTxnManager().registerXATxn 994 (reader.getTxnPrepareXid(), preparedTxn, true); 995 Tracer.trace(Level.INFO, env, 996 "Found unfinished prepare record: id: " + 997 reader.getTxnPrepareId() + 998 " Xid: " + reader.getTxnPrepareXid()); 999 } 1000 } else if (reader.isAbort()) { 1001 1002 abortedTxnIds.add(new Long (reader.getTxnAbortId())); 1003 } else { 1004 1005 committedTxnIds.add(new Long (reader.getTxnCommitId())); 1006 } 1007 } 1008 info.nRepeatIteratorReads += reader.getNRepeatIteratorReads(); 1009 } catch (RuntimeException e) { 1010 traceAndThrowException(reader.getLastLsn(), "undoLNs", e); 1011 } 1012 } 1013 1014 1020 private void redoLNs(RecoveryInfo info, Set lnTypes) 1021 throws IOException , DatabaseException { 1022 1023 long endOfFileLsn = info.nextAvailableLsn; 1024 long rollForwardLsn = info.checkpointStartLsn; 1025 1026 LNFileReader reader = 1027 new LNFileReader(env, readBufferSize, rollForwardLsn, 1028 true, DbLsn.NULL_LSN, endOfFileLsn, null); 1029 1030 Iterator iter = lnTypes.iterator(); 1031 while (iter.hasNext()) { 1032 LogEntryType lnType = (LogEntryType) iter.next(); 1033 reader.addTargetType(lnType); 1034 } 1035 1036 Set countedAbortLsnNodes = new HashSet (); 1038 DbTree dbMapTree = env.getDbMapTree(); 1039 TreeLocation location = new TreeLocation(); 1040 try { 1041 1042 1043 while (reader.readNextEntry()) { 1044 if (reader.isLN()) { 1045 1046 1047 Long txnId = reader.getTxnId(); 1048 1049 1053 boolean processThisLN = false; 1054 boolean lnIsCommitted = false; 1055 boolean lnIsPrepared = false; 1056 Txn preparedTxn = null; 1057 if (txnId == null) { 1058 processThisLN = true; 1059 } else { 1060 lnIsCommitted = committedTxnIds.contains(txnId); 1061 if (!lnIsCommitted) { 1062 preparedTxn = (Txn) preparedTxns.get(txnId); 1063 lnIsPrepared = preparedTxn != null; 1064 } 1065 if (lnIsCommitted || lnIsPrepared) { 1066 processThisLN = true; 1067 } 1068 } 1069 if (processThisLN) { 1070 1071 1072 env.invokeEvictor(); 1073 1074 LN ln = reader.getLN(); 1075 DatabaseId dbId = reader.getDatabaseId(); 1076 DatabaseImpl db = dbMapTree.getDb(dbId); 1077 long logLsn = reader.getLastLsn(); 1078 long treeLsn = DbLsn.NULL_LSN; 1079 1080 1081 if (db != null) { 1082 ln.postFetchInit(db, logLsn); 1083 1084 if (preparedTxn != null) { 1085 preparedTxn.addLogInfo(logLsn); 1086 1087 1093 preparedTxn.lock 1094 (ln.getNodeId(), LockType.WRITE, 1095 false , db); 1096 preparedTxn.setPrepared(true); 1097 } 1098 1099 treeLsn = redo(db, 1100 location, 1101 ln, 1102 reader.getKey(), 1103 reader.getDupTreeKey(), 1104 logLsn, 1105 info); 1106 1107 1113 inListRebuildDbIds.add(dbId); 1114 } 1115 1116 1117 TxnNodeId txnNodeId = null; 1118 if (txnId != null) { 1119 txnNodeId = new TxnNodeId(reader.getNodeId(), 1120 txnId.longValue()); 1121 } 1122 redoUtilizationInfo(logLsn, treeLsn, 1123 reader.getAbortLsn(), 1124 reader.getAbortKnownDeleted(), 1125 reader.getLastEntrySize(), 1126 reader.getKey(), 1127 ln, txnNodeId, 1128 countedAbortLsnNodes); 1129 } 1130 } 1131 } 1132 info.nRepeatIteratorReads += reader.getNRepeatIteratorReads(); 1133 } catch (Exception e) { 1134 traceAndThrowException(reader.getLastLsn(), "redoLns", e); 1135 } 1136 } 1137 1138 1142 private void rebuildINList() 1143 throws DatabaseException { 1144 1145 env.getInMemoryINs().clear(); env.getDbMapTree().rebuildINListMapDb(); 1148 1149 Iterator iter = inListRebuildDbIds.iterator(); 1150 while (iter.hasNext()) { 1151 DatabaseId dbId = (DatabaseId) iter.next(); 1152 1153 if (!dbId.equals(DbTree.ID_DB_ID)) { 1154 DatabaseImpl db = env.getDbMapTree().getDb(dbId); 1155 if (db != null) { 1156 db.getTree().rebuildINList(); 1157 } 1158 } 1159 } 1160 } 1161 1162 1163 private static class TxnNodeId { 1164 long nodeId; 1165 long txnId; 1166 1167 TxnNodeId(long nodeId, long txnId) { 1168 this.nodeId = nodeId; 1169 this.txnId = txnId; 1170 } 1171 1172 1175 public boolean equals(Object obj) { 1176 if (this == obj) { 1177 return true; 1178 } 1179 1180 if (!(obj instanceof TxnNodeId)) { 1181 return false; 1182 } 1183 1184 return ((((TxnNodeId) obj).txnId == txnId) && 1185 (((TxnNodeId) obj).nodeId == nodeId)); 1186 } 1187 1188 public int hashCode() { 1189 return (int) (txnId + nodeId); 1190 } 1191 1192 public String toString() { 1193 return "txnId=" + txnId + "/nodeId=" + nodeId; 1194 } 1195 } 1196 1197 1200 1201 1222 private void replaceOrInsert(DatabaseImpl db, 1223 IN inFromLog, 1224 long logLsn, 1225 long inLsn, 1226 boolean requireExactMatch) 1227 throws DatabaseException { 1228 1229 List trackingList = null; 1230 boolean inFromLogLatchReleased = false; 1231 try { 1232 1233 1240 if (inFromLog.isRoot()) { 1241 if (inFromLog.containsDuplicates()) { 1242 replaceOrInsertDuplicateRoot(db, (DIN) inFromLog, logLsn); 1243 } else { 1244 replaceOrInsertRoot(db, inFromLog, logLsn); 1245 inFromLogLatchReleased = true; 1246 } 1247 } else { 1248 1252 trackingList = new ArrayList (); 1253 replaceOrInsertChild(db, inFromLog, logLsn, inLsn, 1254 trackingList, requireExactMatch); 1255 inFromLogLatchReleased = true; 1256 } 1257 } catch (Exception e) { 1258 String trace = printTrackList(trackingList); 1259 Tracer.trace(db.getDbEnvironment(), "RecoveryManager", 1260 "replaceOrInsert", " lsnFromLog:" + 1261 DbLsn.getNoFormatString(logLsn) + " " + trace, 1262 e); 1263 throw new DatabaseException("lsnFromLog=" + 1264 DbLsn.getNoFormatString(logLsn), e); 1265 } finally { 1266 if (!inFromLogLatchReleased) { 1267 inFromLog.releaseLatchIfOwner(); 1268 } 1269 1270 assert (LatchSupport.countLatchesHeld() == 0): 1271 LatchSupport.latchesHeldToString() + 1272 "LSN = " + DbLsn.toString(logLsn) + 1273 " inFromLog = " + inFromLog.getNodeId(); 1274 1275 } 1276 } 1277 1278 1281 private String printTrackList(List trackingList) { 1282 if (trackingList != null) { 1283 StringBuffer sb = new StringBuffer (); 1284 Iterator iter = trackingList.iterator(); 1285 sb.append("Trace list:"); 1286 sb.append('\n'); 1287 while (iter.hasNext()) { 1288 sb.append((TrackingInfo) iter.next()); 1289 sb.append('\n'); 1290 } 1291 return sb.toString(); 1292 } else { 1293 return null; 1294 } 1295 } 1296 1297 1301 private void replayINDelete(DatabaseImpl db, 1302 long nodeId, 1303 boolean containsDuplicates, 1304 byte[] mainKey, 1305 byte[] dupKey, 1306 long logLsn) 1307 throws DatabaseException { 1308 1309 boolean found = false; 1310 boolean deleted = false; 1311 Tree tree = db.getTree(); 1312 SearchResult result = new SearchResult(); 1313 1314 try { 1315 1316 result = db.getTree().getParentINForChildIN 1317 (nodeId, 1318 containsDuplicates, 1319 false, mainKey, 1321 dupKey, 1322 false, false, -1, null, true); 1328 if (result.parent == null) { 1329 1330 tree.withRootLatchedExclusive(new RootDeleter(tree)); 1331 DbTree dbTree = db.getDbEnvironment().getDbMapTree(); 1332 dbTree.modifyDbRoot(db); 1333 traceRootDeletion(Level.FINE, db); 1334 deleted = true; 1335 } else if (result.exactParentFound) { 1336 1337 found = true; 1338 deleted = result.parent.deleteEntry(result.index, false); 1339 } 1340 } finally { 1341 if (result.parent != null) { 1342 result.parent.releaseLatch(); 1343 } 1344 1345 traceINDeleteReplay 1346 (nodeId, logLsn, found, deleted, result.index, 1347 containsDuplicates); 1348 } 1349 } 1350 1351 1354 private static class RootDeleter implements WithRootLatched { 1355 Tree tree; 1356 RootDeleter(Tree tree) { 1357 this.tree = tree; 1358 } 1359 1360 1363 public IN doWork(ChildReference root) 1364 throws DatabaseException { 1365 1366 tree.setRoot(null, false); 1367 return null; 1368 } 1369 } 1370 1371 1380 private void replaceOrInsertRoot(DatabaseImpl db, IN inFromLog, long lsn) 1381 throws DatabaseException { 1382 1383 boolean success = true; 1384 Tree tree = db.getTree(); 1385 RootUpdater rootUpdater = new RootUpdater(tree, inFromLog, lsn); 1386 try { 1387 1388 tree.withRootLatchedExclusive(rootUpdater); 1389 1390 1391 if (rootUpdater.updateDone()) { 1392 EnvironmentImpl env = db.getDbEnvironment(); 1393 env.getDbMapTree().modifyDbRoot(db); 1394 } 1395 } catch (Exception e) { 1396 success = false; 1397 throw new DatabaseException("lsnFromLog=" + 1398 DbLsn.getNoFormatString(lsn), 1399 e); 1400 } finally { 1401 trace(detailedTraceLevel, 1402 db, TRACE_ROOT_REPLACE, success, inFromLog, 1403 lsn, 1404 null, 1405 true, 1406 rootUpdater.getReplaced(), 1407 rootUpdater.getInserted(), 1408 rootUpdater.getOriginalLsn(), 1409 DbLsn.NULL_LSN, 1410 -1); 1411 } 1412 } 1413 1414 1417 private static class RootUpdater implements WithRootLatched { 1418 private Tree tree; 1419 private IN inFromLog; 1420 private long lsn = DbLsn.NULL_LSN; 1421 private boolean inserted = false; 1422 private boolean replaced = false; 1423 private long originalLsn = DbLsn.NULL_LSN; 1424 1425 RootUpdater(Tree tree, IN inFromLog, long lsn) { 1426 this.tree = tree; 1427 this.inFromLog = inFromLog; 1428 this.lsn = lsn; 1429 } 1430 1431 public IN doWork(ChildReference root) 1432 throws DatabaseException { 1433 1434 ChildReference newRoot = 1435 tree.makeRootChildReference(inFromLog, new byte[0], lsn); 1436 inFromLog.releaseLatch(); 1437 1438 if (root == null) { 1439 tree.setRoot(newRoot, false); 1440 inserted = true; 1441 } else { 1442 originalLsn = root.getLsn(); 1444 1448 if (DbLsn.compareTo(originalLsn, lsn) < 0) { 1449 tree.setRoot(newRoot, false); 1450 replaced = true; 1451 } 1452 } 1453 return null; 1454 } 1455 1456 boolean updateDone() { 1457 return inserted || replaced; 1458 } 1459 1460 boolean getInserted() { 1461 return inserted; 1462 } 1463 1464 boolean getReplaced() { 1465 return replaced; 1466 } 1467 1468 long getOriginalLsn() { 1469 return originalLsn; 1470 } 1471 } 1472 1473 1476 private void replaceOrInsertDuplicateRoot(DatabaseImpl db, 1477 DIN inFromLog, 1478 long lsn) 1479 throws DatabaseException { 1480 1481 boolean found = true; 1482 boolean inserted = false; 1483 boolean replaced = false; 1484 long originalLsn = DbLsn.NULL_LSN; 1485 1486 byte[] mainTreeKey = inFromLog.getMainTreeKey(); 1487 IN parent = null; 1488 int index = -1; 1489 boolean success = false; 1490 try { 1491 1492 1496 parent = db.getTree().searchSplitsAllowed 1497 (mainTreeKey, -1, true ); 1498 assert parent instanceof BIN; 1499 1500 ChildReference newRef = 1501 new ChildReference(inFromLog, mainTreeKey, lsn); 1502 index = parent.insertEntry1(newRef); 1503 if ((index >= 0 && 1504 (index & IN.EXACT_MATCH) != 0)) { 1505 1506 index &= ~IN.EXACT_MATCH; 1507 1508 1516 if (parent.isEntryKnownDeleted(index)) { 1517 1518 parent.setEntry(index, inFromLog, mainTreeKey, 1519 lsn, (byte) 0); 1520 replaced = true; 1521 } else { 1522 originalLsn = parent.getLsn(index); 1523 if (DbLsn.compareTo(originalLsn, lsn) < 0) { 1524 parent.setEntry(index, inFromLog, mainTreeKey, lsn, 1525 parent.getState(index)); 1526 replaced = true; 1527 } 1528 } 1529 } else { 1530 found = false; 1531 } 1532 success = true; 1533 } finally { 1534 if (parent != null) { 1535 parent.releaseLatch(); 1536 } 1537 trace(detailedTraceLevel, 1538 db, 1539 TRACE_DUP_ROOT_REPLACE, success, inFromLog, 1540 lsn, parent, found, 1541 replaced, inserted, originalLsn, DbLsn.NULL_LSN, index); 1542 } 1543 } 1544 1545 private void replaceOrInsertChild(DatabaseImpl db, 1546 IN inFromLog, 1547 long logLsn, 1548 long inLsn, 1549 List trackingList, 1550 boolean requireExactMatch) 1551 throws DatabaseException { 1552 1553 boolean inserted = false; 1554 boolean replaced = false; 1555 long originalLsn = DbLsn.NULL_LSN; 1556 boolean success = false; 1557 SearchResult result = new SearchResult(); 1558 try { 1559 result = db.getTree().getParentINForChildIN 1560 (inFromLog, 1561 requireExactMatch, 1562 false, -1, trackingList); 1565 1566 1580 if (result.parent == null) { 1581 return; } 1583 1584 1585 if (result.index >= 0) { 1586 if (result.parent.getLsn(result.index) == logLsn) { 1587 1588 1589 } else { 1590 1591 1594 if (result.exactParentFound) { 1595 originalLsn = result.parent.getLsn(result.index); 1596 1597 1598 if (DbLsn.compareTo(originalLsn, logLsn) < 0) { 1599 1600 1608 result.parent.updateEntry(result.index, 1609 inFromLog, 1610 inLsn); 1611 replaced = true; 1612 } 1613 } 1614 1615 } 1616 } 1617 1618 1619 success = true; 1620 } finally { 1621 if (result.parent != null) { 1622 result.parent.releaseLatch(); 1623 } 1624 1625 trace(detailedTraceLevel, db, 1626 TRACE_IN_REPLACE, success, inFromLog, 1627 logLsn, result.parent, 1628 result.exactParentFound, replaced, inserted, 1629 originalLsn, DbLsn.NULL_LSN, result.index); 1630 } 1631 } 1632 1633 1664 private long redo(DatabaseImpl db, 1665 TreeLocation location, 1666 LN lnFromLog, 1667 byte[] mainKey, 1668 byte[] dupKey, 1669 long logLsn, 1670 RecoveryInfo info) 1671 throws DatabaseException { 1672 1673 boolean found = false; 1674 boolean replaced = false; 1675 boolean inserted = false; 1676 boolean success = false; 1677 try { 1678 1679 1682 location.reset(); 1683 found = db.getTree().getParentBINForChildLN 1684 (location, mainKey, dupKey, lnFromLog, 1685 true, false, true, true); 1690 if (!found && (location.bin == null)) { 1691 1692 1696 success = true; 1697 return DbLsn.NULL_LSN; 1698 } 1699 1700 1703 if (lnFromLog.containsDuplicates()) { 1704 if (found) { 1705 1706 1710 DIN duplicateRoot = (DIN) 1711 location.bin.fetchTarget(location.index); 1712 if (DbLsn.compareTo(logLsn, location.childLsn) >= 0) { 1713 1714 duplicateRoot.latch(); 1715 duplicateRoot.updateDupCountLNRefAndNullTarget(logLsn); 1716 duplicateRoot.releaseLatch(); 1717 } 1718 } 1719 } else { 1720 if (found) { 1721 1722 1725 info.lnFound++; 1726 1727 if (DbLsn.compareTo(logLsn, location.childLsn) > 0) { 1728 info.lnReplaced++; 1729 replaced = true; 1730 1731 1737 location.bin.updateEntry(location.index, 1738 null, 1739 logLsn); 1740 } 1741 1742 1747 if (DbLsn.compareTo(logLsn, location.childLsn) >= 0 && 1748 lnFromLog.isDeleted()) { 1749 location.bin.setKnownDeletedLeaveTarget 1750 (location.index); 1751 byte[] deletedKey = location.bin.containsDuplicates() ? 1752 dupKey : mainKey; 1753 1754 1758 if (deletedKey != null) { 1759 db.getDbEnvironment().addToCompressorQueue 1760 (location.bin, 1761 new Key(deletedKey), 1762 false); } 1764 } 1765 1766 } else { 1767 1771 info.lnNotFound++; 1772 if (!lnFromLog.isDeleted()) { 1773 info.lnInserted++; 1774 inserted = true; 1775 boolean insertOk = 1776 insertRecovery(db, location, logLsn); 1777 assert insertOk; 1778 } 1779 } 1780 } 1781 success = true; 1782 return found ? location.childLsn : DbLsn.NULL_LSN; 1783 } finally { 1784 if (location.bin != null) { 1785 location.bin.releaseLatchIfOwner(); 1786 } 1787 trace(detailedTraceLevel, db, 1788 TRACE_LN_REDO, success, lnFromLog, 1789 logLsn, location.bin, found, 1790 replaced, inserted, 1791 location.childLsn, DbLsn.NULL_LSN, location.index); 1792 } 1793 } 1794 1795 1826 public static void undo(Level traceLevel, 1827 DatabaseImpl db, 1828 TreeLocation location, 1829 LN lnFromLog, 1830 byte[] mainKey, 1831 byte[] dupKey, 1832 long logLsn, 1833 long abortLsn, 1834 boolean abortKnownDeleted, 1835 RecoveryInfo info, 1836 boolean splitsAllowed) 1837 throws DatabaseException { 1838 1839 boolean found = false; 1840 boolean replaced = false; 1841 boolean success = false; 1842 1843 try { 1844 1845 1848 location.reset(); 1849 found = db.getTree().getParentBINForChildLN 1850 (location, mainKey, dupKey, lnFromLog, splitsAllowed, 1851 true, false, true); 1855 1858 if (lnFromLog.containsDuplicates()) { 1859 1860 1864 if (found) { 1865 DIN duplicateRoot = (DIN) 1866 location.bin.fetchTarget(location.index); 1867 duplicateRoot.latch(); 1868 try { 1869 if (DbLsn.compareTo(logLsn, location.childLsn) == 0) { 1870 1871 duplicateRoot. 1872 updateDupCountLNRefAndNullTarget(abortLsn); 1873 replaced = true; 1874 } 1875 } finally { 1876 duplicateRoot.releaseLatch(); 1877 } 1878 } 1879 } else { 1880 if (found) { 1881 1882 if (info != null) { 1883 info.lnFound++; 1884 } 1885 boolean updateEntry = 1886 DbLsn.compareTo(logLsn, location.childLsn) == 0; 1887 if (updateEntry) { 1888 if (abortLsn == DbLsn.NULL_LSN) { 1889 1890 1896 location.bin. 1897 setKnownDeletedLeaveTarget(location.index); 1898 byte[] deletedKey = 1899 location.bin.containsDuplicates() ? 1900 dupKey : mainKey; 1901 db.getDbEnvironment().addToCompressorQueue 1902 (location.bin, 1903 new Key(deletedKey), 1904 false); 1906 } else { 1907 1908 1913 if (info != null) { 1914 info.lnReplaced++; 1915 } 1916 replaced = true; 1917 location.bin.updateEntry(location.index, 1918 null, 1919 abortLsn); 1920 if (abortKnownDeleted) { 1921 location.bin.setKnownDeleted(location.index); 1922 } else { 1923 location.bin.clearKnownDeleted(location.index); 1924 } 1925 } 1926 1927 1933 location.bin.clearPendingDeleted(location.index); 1934 } 1935 1936 } else { 1937 1938 1941 if (info != null) { 1942 info.lnNotFound++; 1943 } 1944 } 1945 } 1946 1947 success = true; 1948 } finally { 1949 1953 trace(traceLevel, db, TRACE_LN_UNDO, success, lnFromLog, 1954 logLsn, location.bin, found, replaced, false, 1955 location.childLsn, abortLsn, location.index); 1956 } 1957 } 1958 1959 1974 private static boolean insertRecovery(DatabaseImpl db, 1975 TreeLocation location, 1976 long logLsn) 1977 throws DatabaseException { 1978 1979 1980 ChildReference newLNRef = 1981 new ChildReference(null, location.lnKey, logLsn); 1982 1983 BIN parentBIN = location.bin; 1984 int entryIndex = parentBIN.insertEntry1(newLNRef); 1985 1986 if ((entryIndex & IN.INSERT_SUCCESS) == 0) { 1987 1988 1991 entryIndex &= ~IN.EXACT_MATCH; 1992 1993 boolean canOverwrite = false; 1994 if (parentBIN.isEntryKnownDeleted(entryIndex)) { 1995 canOverwrite = true; 1996 } else { 1997 1998 2003 LN currentLN = (LN) parentBIN.fetchTarget(entryIndex); 2004 2005 if (currentLN == null || currentLN.isDeleted()) { 2006 canOverwrite = true; 2007 } 2008 2009 2013 parentBIN.updateEntry(entryIndex, null); 2014 } 2015 2016 if (canOverwrite) { 2017 parentBIN.updateEntry(entryIndex, null, logLsn, 2018 location.lnKey); 2019 parentBIN.clearKnownDeleted(entryIndex); 2020 location.index = entryIndex; 2021 return true; 2022 } else { 2023 return false; 2024 } 2025 } 2026 location.index = entryIndex & ~IN.INSERT_SUCCESS; 2027 return true; 2028 } 2029 2030 2033 private void redoUtilizationInfo(long logLsn, 2034 long treeLsn, 2035 long abortLsn, 2036 boolean abortKnownDeleted, 2037 int logEntrySize, 2038 byte[] key, 2039 LN ln, 2040 TxnNodeId txnNodeId, 2041 Set countedAbortLsnNodes) 2042 throws DatabaseException { 2043 2044 UtilizationTracker tracker = env.getUtilizationTracker(); 2045 2046 2050 if (ln.isDeleted()) { 2051 Long logFileNum = new Long (DbLsn.getFileNumber(logLsn)); 2052 long fileSummaryLsn = 2053 DbLsn.longToLsn((Long ) fileSummaryLsns.get(logFileNum)); 2054 int cmpFsLsnToLogLsn = 2055 (fileSummaryLsn != DbLsn.NULL_LSN) ? 2056 DbLsn.compareTo(fileSummaryLsn, logLsn) : -1; 2057 if (cmpFsLsnToLogLsn < 0) { 2058 tracker.countObsoleteNode(logLsn, null, logEntrySize); 2059 } 2060 } 2061 2062 2063 if (treeLsn != DbLsn.NULL_LSN) { 2064 int cmpLogLsnToTreeLsn = DbLsn.compareTo(logLsn, treeLsn); 2065 2066 2071 if (cmpLogLsnToTreeLsn != 0) { 2072 long newLsn = (cmpLogLsnToTreeLsn < 0) ? treeLsn : logLsn; 2073 long oldLsn = (cmpLogLsnToTreeLsn > 0) ? treeLsn : logLsn; 2074 Long oldLsnFile = new Long (DbLsn.getFileNumber(oldLsn)); 2075 long oldFsLsn = 2076 DbLsn.longToLsn((Long ) fileSummaryLsns.get(oldLsnFile)); 2077 int cmpOldFsLsnToNewLsn = 2078 (oldFsLsn != DbLsn.NULL_LSN) ? 2079 DbLsn.compareTo(oldFsLsn, newLsn) : -1; 2080 if (cmpOldFsLsnToNewLsn < 0) { 2081 2082 int oldSize = 0; 2083 if (oldLsn == logLsn) { 2084 oldSize = logEntrySize; 2085 } else if (env.getCleaner().getFetchObsoleteSize()) { 2086 try { 2087 LN oldLn = (LN) env.getLogManager().get(oldLsn); 2088 oldSize = oldLn.getTotalLastLoggedSize(key); 2089 } catch (LogFileNotFoundException e) { 2090 2091 } 2092 } 2093 tracker.countObsoleteNode(oldLsn, null, oldSize); 2094 } 2095 } 2096 2097 2104 if (cmpLogLsnToTreeLsn <= 0 && 2105 abortLsn != DbLsn.NULL_LSN && 2106 !abortKnownDeleted && 2107 !countedAbortLsnNodes.contains(txnNodeId)) { 2108 2109 Long abortFileNum = new Long (DbLsn.getFileNumber(abortLsn)); 2110 long abortFsLsn = 2111 DbLsn.longToLsn((Long ) fileSummaryLsns.get(abortFileNum)); 2112 int cmpAbortFsLsnToLogLsn = 2113 (abortFsLsn != DbLsn.NULL_LSN) ? 2114 DbLsn.compareTo(abortFsLsn, logLsn) : -1; 2115 if (cmpAbortFsLsnToLogLsn < 0) { 2116 2117 2123 tracker.countObsoleteNodeInexact(abortLsn, null, 0); 2124 2125 2126 countedAbortLsnNodes.add(txnNodeId); 2127 } 2128 } 2129 } 2130 } 2131 2132 2135 private void undoUtilizationInfo(LN ln, 2136 long logLsn, 2137 long abortLsn, 2138 boolean abortKnownDeleted, 2139 int logEntrySize, 2140 TxnNodeId txnNodeId, 2141 Map countedFileSummaries, 2142 Set countedAbortLsnNodes) { 2143 2144 UtilizationTracker tracker = env.getUtilizationTracker(); 2145 2146 2147 Long logFileNum = new Long (DbLsn.getFileNumber(logLsn)); 2148 long fileSummaryLsn = 2149 DbLsn.longToLsn((Long ) fileSummaryLsns.get(logFileNum)); 2150 int cmpFsLsnToLogLsn = (fileSummaryLsn != DbLsn.NULL_LSN) ? 2151 DbLsn.compareTo(fileSummaryLsn, logLsn) : -1; 2152 2153 2157 if (cmpFsLsnToLogLsn < 0) { 2158 tracker.countObsoleteNode(logLsn, null, logEntrySize); 2159 } 2160 2161 2166 if (cmpFsLsnToLogLsn > 0) { 2167 Long countedFile = (Long ) countedFileSummaries.get(txnNodeId); 2168 if (countedFile == null || 2169 countedFile.longValue() > logFileNum.longValue()) { 2170 2171 2175 if (!ln.isDeleted()) { 2176 tracker.countObsoleteNode(logLsn, null, logEntrySize); 2177 } 2178 2179 countedFileSummaries.put(txnNodeId, logFileNum); 2180 } 2181 } 2182 } 2183 2184 2187 private String passStartHeader(int passNum) { 2188 return "Recovery Pass " + passNum + " start: "; 2189 } 2190 2191 2194 private String passEndHeader(int passNum, long start, long end) { 2195 return "Recovery Pass " + passNum + " end (" + 2196 (end-start) + "): "; 2197 } 2198 2199 2205 private static void trace(Level level, 2206 DatabaseImpl database, 2207 String debugType, 2208 boolean success, 2209 Node node, 2210 long logLsn, 2211 IN parent, 2212 boolean found, 2213 boolean replaced, 2214 boolean inserted, 2215 long replacedLsn, 2216 long abortLsn, 2217 int index) { 2218 Logger logger = database.getDbEnvironment().getLogger(); 2219 Level useLevel= level; 2220 if (!success) { 2221 useLevel = Level.SEVERE; 2222 } 2223 if (logger.isLoggable(useLevel)) { 2224 StringBuffer sb = new StringBuffer (); 2225 sb.append(debugType); 2226 sb.append(" success=").append(success); 2227 sb.append(" node="); 2228 sb.append(node.getNodeId()); 2229 sb.append(" lsn="); 2230 sb.append(DbLsn.getNoFormatString(logLsn)); 2231 if (parent != null) { 2232 sb.append(" parent=").append(parent.getNodeId()); 2233 } 2234 sb.append(" found="); 2235 sb.append(found); 2236 sb.append(" replaced="); 2237 sb.append(replaced); 2238 sb.append(" inserted="); 2239 sb.append(inserted); 2240 if (replacedLsn != DbLsn.NULL_LSN) { 2241 sb.append(" replacedLsn="); 2242 sb.append(DbLsn.getNoFormatString(replacedLsn)); 2243 } 2244 if (abortLsn != DbLsn.NULL_LSN) { 2245 sb.append(" abortLsn="); 2246 sb.append(DbLsn.getNoFormatString(abortLsn)); 2247 } 2248 sb.append(" index=").append(index); 2249 logger.log(useLevel, sb.toString()); 2250 } 2251 } 2252 2253 2258 private void traceINDeleteReplay(long nodeId, 2259 long logLsn, 2260 boolean found, 2261 boolean deleted, 2262 int index, 2263 boolean isDuplicate) { 2264 Logger logger = env.getLogger(); 2265 if (logger.isLoggable(detailedTraceLevel)) { 2266 StringBuffer sb = new StringBuffer (); 2267 sb.append((isDuplicate) ? 2268 TRACE_IN_DUPDEL_REPLAY : 2269 TRACE_IN_DEL_REPLAY); 2270 sb.append(" node=").append(nodeId); 2271 sb.append(" lsn=").append(DbLsn.getNoFormatString(logLsn)); 2272 sb.append(" found=").append(found); 2273 sb.append(" deleted=").append(deleted); 2274 sb.append(" index=").append(index); 2275 logger.log(detailedTraceLevel, sb.toString()); 2276 } 2277 } 2278 2279 private void traceAndThrowException(long badLsn, 2280 String method, 2281 Exception originalException) 2282 throws DatabaseException { 2283 String badLsnString = DbLsn.getNoFormatString(badLsn); 2284 Tracer.trace(env, 2285 "RecoveryManager", 2286 method, 2287 "last LSN = " + badLsnString, 2288 originalException); 2289 throw new DatabaseException("last LSN=" + badLsnString, 2290 originalException); 2291 } 2292 2293 2297 public static void traceRootDeletion(Level level, DatabaseImpl database) { 2298 Logger logger = database.getDbEnvironment().getLogger(); 2299 if (logger.isLoggable(level)) { 2300 StringBuffer sb = new StringBuffer (); 2301 sb.append(TRACE_ROOT_DELETE); 2302 sb.append(" Dbid=").append(database.getId()); 2303 logger.log(level, sb.toString()); 2304 } 2305 } 2306} 2307 | Popular Tags |