📄 filelogger.java
字号:
undoInstant = logIn.readLong(); SanityManager.DEBUG( LogToFile.DBG_FLAG, "scanned " + tranId + " : " + op + " instant = " + LogCounter.toDebugString(instant) + " undoInstant : " + LogCounter.toDebugString(undoInstant)); } else { SanityManager.DEBUG( LogToFile.DBG_FLAG, "scanned " + tranId + " : " + op + " instant = " + LogCounter.toDebugString(instant) + " logEnd = " + LogCounter.toDebugString(logEnd) + " logIn at " + logIn.getPosition() + " available " + logIn.available()); } // we only want to dump the log, don't touch it if (SanityManager.DEBUG_ON(LogToFile.DUMP_LOG_ONLY)) continue; } } // if the redo scan is between the undoLWM and redoLWM, we only // need to redo begin and end tran. Everything else has // already been flushed by checkpoint if (redoLWM != LogCounter.INVALID_LOG_INSTANT && instant < redoLWM) { if (!(record.isFirst() || record.isComplete() || record.isPrepare())) { continue; } } // get the transaction tranId = record.getTransactionId(); // if this transaction is known to the transaction factory, make // the recoveryTransaction assume its identitiy and properties // otherwise, make it known to the transaction factory if (!transFactory.findTransaction(tranId, recoveryTransaction)) { // transaction not found if (redoLWM != LogCounter.INVALID_LOG_INSTANT && instant < redoLWM && (record.isPrepare() || record.isComplete())) { // What is happening here is that a transaction that // started before the undoLWM has commited by the time // the checkpoint undoLWM was taken. Hence, we only // see the tail end of its log record and its endXact // record. // // NOTE: // Since we didn't see its beginXact, we cannot do the // endXact's doMe either. Also if the endXact, is // actually just a prepare, we don't need to do // anything as the transaction will commit or abort // prior to point we are recovering to. // If it is deemed necessary to do the endXact's doMe, // then we should start the transaction right here. // For now, just completely ignore this transaction // etranCount++; continue; } if ((ttabInstant == LogCounter.INVALID_LOG_INSTANT) && !record.isFirst()) { throw StandardException.newException( SQLState.LOG_UNEXPECTED_RECOVERY_PROBLEM, MessageService.getTextMessage(MessageId.LOG_RECORD_NOT_FIRST,tranId)); } if (SanityManager.DEBUG) { // if we dumped the transaction table but see a non // BeginXact record after the transaction table dump // instant, error. if (ttabInstant != LogCounter.INVALID_LOG_INSTANT) { if (instant > ttabInstant && !record.isFirst()) { SanityManager.THROWASSERT( "log record is Not first but transaction " + "is not in transaction table (2) : " + tranId); } // If we dump the transaction table and the table // does not have the transaction, and we see this // beginXact before the ttab instant, we could have // igored it because we "know" that we should see // the endXact before the ttab instant also. // Leave it in just in case. } } btranCount++; // the long transaction ID is embedded in the beginXact log // record. The short ID is stored in the log record. recoveryTransaction.setTransactionId( record.getLoggable(), tranId); } else { // recoveryTransaction found if ((ttabInstant == LogCounter.INVALID_LOG_INSTANT) && record.isFirst()) { throw StandardException.newException( SQLState.LOG_UNEXPECTED_RECOVERY_PROBLEM, MessageService.getTextMessage(MessageId.LOG_RECORD_FIRST, tranId)); } if (SanityManager.DEBUG) { if (ttabInstant != LogCounter.INVALID_LOG_INSTANT && instant > ttabInstant && record.isFirst()) { SanityManager.THROWASSERT( "log record is first but transaction is " + "already in transaction table (3): " + tranId); } if (record.isPrepare()) prepareCount++; } // if we have a transaction table dumped with the // checkpoint log record, then during the redo scan we may // see the beginXact of a transaction which is already in // the transaction table, just ignore it if it is after the // redoLWM but before the transaction table instant. We // still need to redo any database changes but since the // transaction is already recorded in the transaction // table, ignore it. // if (record.isFirst()) { btranCount++; continue; } } op = record.getLoggable(); if (SanityManager.DEBUG) { if (!record.isCLR()) { if (logIn.available() < 4) { SanityManager.THROWASSERT( "not enough bytes read in : " + logIn.available() + " for " + op + " instant " + LogCounter.toDebugString(instant)); } } } if (SanityManager.DEBUG) { SanityManager.ASSERT( !recoveryTransaction.handlesPostTerminationWork(), "recovery transaction handles post termination work"); } if (op.needsRedo(recoveryTransaction)) { redoCount++; if (record.isCLR()) { clrCount++; // the log operation is not complete, the operation to // undo is stashed away at the undoInstant. // Reconstitute that first. if (SanityManager.DEBUG) SanityManager.ASSERT(op instanceof Compensation); // this value may be set by sanity xxxx if (undoInstant == 0) undoInstant = logIn.readLong(); if (undoScan == null) { undoScan = (StreamLogScan) logFactory.openForwardsScan( undoInstant,(LogInstant)null); } else { undoScan.resetPosition(new LogCounter(undoInstant)); } // undoScan now positioned at the beginning of the log // record was rolled back by this CLR. // The scan is a forward one so getNextRecord will get // the log record that needs to be rolled back. // reuse the buffer in logIn and logIn since CLR // has no optional data and has no use for them anymore logIn.clearLimit(); LogRecord undoRecord = undoScan.getNextRecord(logIn, null, 0); Undoable undoOp = undoRecord.getUndoable(); if (SanityManager.DEBUG) { SanityManager.DEBUG( LogToFile.DBG_FLAG, "Redoing CLR: undoInstant = " + LogCounter.toDebugString(undoInstant) + " clrinstant = " + LogCounter.toDebugString(instant)); SanityManager.ASSERT( undoRecord.getTransactionId().equals(tranId)); SanityManager.ASSERT(undoOp != null); } ((Compensation)op).setUndoOp(undoOp); } // at this point, logIn points to the optional // data of the loggable that is to be redone or to be // rolled back if (SanityManager.DEBUG) { if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) { SanityManager.DEBUG( LogToFile.DBG_FLAG, "redoing " + op + " instant = " + LogCounter.toDebugString(instant)); } } int dataLength = logIn.readInt(); logIn.setLimit(logIn.getPosition(), dataLength); // even though the log has already been written, we need to // tie the page to the log stream so that if redo failed // for some reasons, the log factory's corruption will stop // the corrupt page from flushing to disk. op.doMe( recoveryTransaction, new LogCounter(instant), logIn); op.releaseResource(recoveryTransaction); op = null; } // RESOLVE: to speed up undo, may want to update the // LastLogInstant in the transaction table. // Right now, undo always start from the end of the log. // one last thing, if this is the last log record of the // transaction, then commit the transaction and clean up // // 'commit' even though the transaction maybe a rollback // because we already did all the rollback work when redoing // the CLRs. Commit will only flush the log if this session // has written any transaction, so in this case, it is a noop. if (record.isComplete()) { etranCount++; if (SanityManager.DEBUG) SanityManager.ASSERT( !recoveryTransaction.handlesPostTerminationWork(), "recovery xact handles post termination work"); recoveryTransaction.commit(); } } } catch (StandardException se) { throw StandardException.newException( SQLState.LOG_REDO_FAILED, se, op); } finally { // close all the io streams redoScan.close(); redoScan = null; if (undoScan != null) { undoScan.close(); undoScan = null; } if (op != null) op.releaseResource(recoveryTransaction); } if (SanityManager.DEBUG) { if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) { SanityManager.DEBUG( LogToFile.DBG_FLAG, "----------------------------------------------------\n" + "End of recovery redo\n" + "Scanned = " + scanCount + " log records" + ", redid = " + redoCount + " ( clr = " + clrCount + " )" + " begintran = " + btranCount + " endtran = " + etranCount + " preparetran = " + prepareCount + "\n log ends at " + LogCounter.toDebugString(logEnd) + "\n----------------------------------------------------\n"); } } if (SanityManager.DEBUG) { // make sure logEnd and instant is consistent if (instant != LogCounter.INVALID_LOG_INSTANT) { SanityManager.ASSERT( LogCounter.getLogFileNumber(instant) == LogCounter.getLogFileNumber(logEnd) && LogCounter.getLogFilePosition(instant) <= LogCounter.getLogFilePosition(logEnd)); } else { SanityManager.ASSERT(logEnd == LogCounter.INVALID_LOG_INSTANT); } } // logEnd is the last good log record position in the log return logEnd; } /** Read the next log record from the scan. <P>MT - caller must provide synchronization (right now, it is only called in recovery to find the checkpoint log record. When this method is called by a more general audience, MT must be revisited). @param scan an opened log scan @param size estimated size of the log record @return the log operation that is the next in the scan, or null if no more log operation in the log scan @exception IOException Error reading the log file @exception StandardException Standard Cloudscape error policy @exception ClassNotFoundException log corrupted */ protected Loggable readLogRecord(StreamLogScan scan, int size) throws IOException, StandardException, ClassNotFoundException { Loggable lop = null; ArrayInputStream logInputBuffer = new ArrayInputStream(new byte[size]); LogRecord record = scan.getNextRecord(logInputBuffer, null, 0); if (record != null) lop = record.getLoggable(); return lop; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -