internal FileLogRecord(FileLogRecordStream stream) { this.stream = stream; }
// During WriteRestarArea, we truncate all records before the new base sequence number. // The new base sequence number is recorded in the restart-area record. // If truncate failed during WriteRestartArea, then the records before the new base seq number // will still be present in the log. During recovery, we will cleanup the log by removing these records. // Recovery steps - // Scan the log backwards // Stop when the last restart area is found // Truncate the log if needed private void Recover() { SequenceNumber first; SequenceNumber last; this.log.GetLogLimits(out first, out last); // Internal knowledge - if last < first, log is empty if (last < first) return; SequenceNumber sn = last; while (sn != SequenceNumber.Invalid && first <= sn && sn <= last) { FileLogRecordStream stream = new FileLogRecordStream(log, sn); if (stream.Header.IsRestartArea) { this.lastRestartArea = stream.RecordSequenceNumber; // if the base sequence number is different from // the next undo lsn, then we crashed during or // before truncate. Perform the truncate now. if (first < stream.Header.NextUndoLsn) { if (stream.Header.NextUndoLsn == SequenceNumber.Invalid) { // WriteRestartArea was called with LastSequenceNumber if (first != stream.RecordSequenceNumber) { this.newBaseSeqNum = stream.RecordSequenceNumber; } } else { this.newBaseSeqNum = stream.Header.NextUndoLsn; } // This method is called from the constructor. So no need to take a write lock. if (this.newBaseSeqNum != SequenceNumber.Invalid) { try { log.TruncatePrefix(this.newBaseSeqNum); this.newBaseSeqNum = SequenceNumber.Invalid; } #pragma warning suppress 56500 catch (Exception exception) { // Truncate failed again. We were unable to cleanup the log. this.truncateFailed = true; if (Fx.IsFatal(exception)) throw; } } } break; } sn = stream.PrevLsn; } }
public bool MoveNext() { if (this.disposed) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ObjectDisposed()); } if (this.current == SequenceNumber.Invalid) { return(false); } if (!this.enumStarted) { this.enumStarted = true; } else { switch (this.logRecordEnum) { case LogRecordEnumeratorType.Next: this.current = this.stream.NextLsn; break; case LogRecordEnumeratorType.Previous: this.current = this.stream.Header.PreviousLsn; break; case LogRecordEnumeratorType.User: this.current = this.stream.Header.NextUndoLsn; break; } } SequenceNumber first; SequenceNumber last; log.GetLogLimits(out first, out last); if (this.current < first || last < this.current || this.current == SequenceNumber.Invalid) { this.record = null; return(false); } this.stream = new FileLogRecordStream(this.log, this.current); if (!this.enumRestartAreas && this.stream.Header.IsRestartArea) { if (this.logRecordEnum == LogRecordEnumeratorType.Next) { // Move to the next record after restart area. return(MoveNext()); } else { // We have hit a restart area. // Restart areas have special values for prev and next undo in the header. // Cannot enumerate further. this.record = null; return(false); } } this.record = new FileLogRecord(this.stream); return(true); }
// During WriteRestarArea, we truncate all records before the new base sequence number. // The new base sequence number is recorded in the restart-area record. // If truncate failed during WriteRestartArea, then the records before the new base seq number // will still be present in the log. During recovery, we will cleanup the log by removing these records. // Recovery steps - // Scan the log backwards // Stop when the last restart area is found // Truncate the log if needed private void Recover() { SequenceNumber first; SequenceNumber last; this.log.GetLogLimits(out first, out last); // Internal knowledge - if last < first, log is empty if (last < first) { return; } SequenceNumber sn = last; while (sn != SequenceNumber.Invalid && first <= sn && sn <= last) { FileLogRecordStream stream = new FileLogRecordStream(log, sn); if (stream.Header.IsRestartArea) { this.lastRestartArea = stream.RecordSequenceNumber; // if the base sequence number is different from // the next undo lsn, then we crashed during or // before truncate. Perform the truncate now. if (first < stream.Header.NextUndoLsn) { if (stream.Header.NextUndoLsn == SequenceNumber.Invalid) { // WriteRestartArea was called with LastSequenceNumber if (first != stream.RecordSequenceNumber) { this.newBaseSeqNum = stream.RecordSequenceNumber; } } else { this.newBaseSeqNum = stream.Header.NextUndoLsn; } // This method is called from the constructor. So no need to take a write lock. if (this.newBaseSeqNum != SequenceNumber.Invalid) { try { log.TruncatePrefix(this.newBaseSeqNum); this.newBaseSeqNum = SequenceNumber.Invalid; } #pragma warning suppress 56500 catch (Exception exception) { // Truncate failed again. We were unable to cleanup the log. this.truncateFailed = true; if (Fx.IsFatal(exception)) { throw; } } } } break; } sn = stream.PrevLsn; } }