File: System\IO\Log\FileLogRecordEnumerator.cs
Project: ndp\cdf\src\NetFx35\System.IO.Log\System.IO.Log.csproj (System.IO.Log)
//-----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------------------------
namespace System.IO.Log
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
 
    internal class FileLogRecordEnumerable : IEnumerable<LogRecord>
    {
        LogRecordEnumeratorType logRecordEnum;
        SimpleFileLog log;
        SequenceNumber start;
        bool enumRestartAreas;
 
        internal FileLogRecordEnumerable(
            SimpleFileLog log, 
            SequenceNumber start, 
            LogRecordEnumeratorType logRecordEnum,
            bool enumRestartAreas)
        {
            this.log = log;
            this.start = start;
            this.logRecordEnum = logRecordEnum;
            this.enumRestartAreas = enumRestartAreas;
        }
 
        IEnumerator IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }
        
        public IEnumerator<LogRecord> GetEnumerator()
        {
            return new FileLogRecordEnumerator(
                                        log, 
                                        start, 
                                        logRecordEnum, 
                                        enumRestartAreas);
        }
    }
 
    internal class FileLogRecordEnumerator : IEnumerator<LogRecord>
    {
        FileLogRecordStream stream = null;
        FileLogRecord record = null;
        bool enumStarted = false;
        SequenceNumber start;
        SequenceNumber current;
        LogRecordEnumeratorType logRecordEnum;
        SimpleFileLog log;
        bool disposed = false;
        bool enumRestartAreas;
 
        internal FileLogRecordEnumerator(
            SimpleFileLog log,
            SequenceNumber start,
            LogRecordEnumeratorType logRecordEnum,
            bool enumRestartAreas)
        {
            this.log = log;
            this.start = start;
            this.current = start;
            this.logRecordEnum = logRecordEnum;
            this.enumRestartAreas = enumRestartAreas;
        }
 
        object IEnumerator.Current
        {
            get 
            {
                return this.Current;
            }
        }
        
        public LogRecord Current
        {
            get 
            {
                if (this.disposed)
#pragma warning suppress 56503
                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ObjectDisposed());
 
// IEnumerable interface contract for "current" member can throw InvalidOperationException. Suppressing this warning.  
 
                if (!this.enumStarted)
#pragma warning suppress 56503
                   throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.EnumNotStarted());
 
                if (this.record == null)
#pragma warning suppress 56503
                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.EnumEnded());
 
                return this.record;
            }
        }
 
 
        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;
        }
 
        public void Reset()
        {
            if (this.disposed)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ObjectDisposed());
 
            this.enumStarted = false;
            this.current = this.start;
            this.record = null;
        }
 
        public void Dispose()
        {
            this.disposed = true;
        }
    }
}