FileRecordSequence.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / cdf / src / WCF / Log / System / IO / Log / FileRecordSequence.cs / 1305376 / FileRecordSequence.cs

                            //------------------------------------------------------------ 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------
namespace System.IO.Log
{ 
    using System;
    using System.Collections; 
    using System.Collections.Generic; 
    using System.IO;
    using System.Security.AccessControl; 
    using System.Runtime;
    using System.Runtime.InteropServices;
    using System.Security.Permissions;
    using System.Diagnostics; 
    using System.Threading;
 
    // FileRecordSequence uses Simple file log to write records to a file. 
    public sealed class FileRecordSequence : IRecordSequence
    { 
        SimpleFileLog log;
        bool retryAppend;
        object syncTailPinned = new object();
        bool tailPinnedCalled = false; 
        FileAccess access;
        FileRecordSequenceHelper frsHelper; 
        long reservedBytes; 
        object syncReservedBytes = new object();
        int tailPinnedThreadID = -1; 

        public FileRecordSequence(string path) : this(path, FileAccess.ReadWrite, 0) { }

        public FileRecordSequence(string path, FileAccess access) : this(path, access, 0) { } 

        [PermissionSetAttribute(SecurityAction.Demand, Name="FullTrust")] 
        public FileRecordSequence(string path, FileAccess access, int size) 
        {
            if (size < 0) 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ArgumentOutOfRange("size"));

            this.access = access;
            this.log = new SimpleFileLog(Path.GetFullPath(path), size); 
            this.frsHelper = new FileRecordSequenceHelper(this.log);
            this.reservedBytes = 0; 
        } 

        public SequenceNumber BaseSequenceNumber 
        {
            get { return this.frsHelper.BaseSequenceNumber; }
        }
 
        public SequenceNumber LastSequenceNumber
        { 
            get { return this.frsHelper.LastSequenceNumber; } 
        }
 
        public long MaximumRecordLength
        {
            get
            { 
                return Int32.MaxValue;
            } 
        } 

        public long ReservedBytes 
        {
            get
            {
                return this.reservedBytes; 
            }
        } 
 

        public bool RetryAppend 
        {
            get { return this.retryAppend; }
            set { this.retryAppend = value; }
        } 

 
        public SequenceNumber RestartSequenceNumber 
        {
            get { return this.frsHelper.RestartSequenceNumber; } 
        }

        public event EventHandler TailPinned;
 
        public void AdvanceBaseSequenceNumber(
            SequenceNumber newBaseSequenceNumber) 
        { 
            this.frsHelper.AdvanceBaseSequeceNumber(newBaseSequenceNumber);
        } 

        internal void AddReservation(long reservation)
        {
            lock (this.syncReservedBytes) 
            {
                this.reservedBytes += reservation; 
            } 
        }
 
        internal void RemoveReservation(long reservation)
        {
            lock (this.syncReservedBytes)
            { 
                this.reservedBytes -= reservation;
            } 
        } 

        public SequenceNumber Append( 
            ArraySegment data,
            SequenceNumber nextUndoRecord,
            SequenceNumber previousRecord,
            RecordAppendOptions recordAppendOptions) 
        {
            return Append(new ArraySegment[] { data }, 
                          nextUndoRecord, 
                          previousRecord,
                          recordAppendOptions); 
        }

        public SequenceNumber Append(
            ArraySegment data, 
            SequenceNumber nextUndoRecord,
            SequenceNumber previousRecord, 
            RecordAppendOptions recordAppendOptions, 
            ReservationCollection reservations)
        { 
            return Append(new ArraySegment[] { data },
                          nextUndoRecord,
                          previousRecord,
                          recordAppendOptions, 
                          reservations);
        } 
 
        public SequenceNumber Append(
            IList> data, 
            SequenceNumber nextUndoRecord,
            SequenceNumber previousRecord,
            RecordAppendOptions recordAppendOptions)
        { 
            if (data == null)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ArgumentNull("data")); 
            }
 
            if ((this.access & FileAccess.Write) == 0)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.NotSupported(SR.NotSupported_ReadOnly));
            } 

            if(recordAppendOptions > (RecordAppendOptions.ForceAppend | RecordAppendOptions.ForceFlush) || 
               recordAppendOptions < RecordAppendOptions.None) 
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ArgumentOutOfRange("recordAppendOptions")); 
            }

            SequenceNumber sn;
            bool forceFlush = (recordAppendOptions & RecordAppendOptions.ForceFlush) != 0; 
            try
            { 
                sn = frsHelper.Append(data, nextUndoRecord, previousRecord, forceFlush); 
            }
            catch (SequenceFullException) 
            {
                RaiseTailPinnedEvent();

                if (this.RetryAppend) 
                {
                    sn = frsHelper.Append(data, nextUndoRecord, previousRecord, forceFlush); 
                } 
                else
                { 
                    throw;
                }
            }
 
            return sn;
        } 
 

        public SequenceNumber Append( 
            IList> data,
            SequenceNumber nextUndoRecord,
            SequenceNumber previousRecord,
            RecordAppendOptions recordAppendOptions, 
            ReservationCollection reservations)
        { 
            int size = 0; 

            if (reservations == null) 
            {
                return Append(data, nextUndoRecord, previousRecord, recordAppendOptions);
            }
 
            if (data == null)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ArgumentNull("data")); 
            }
 
            FileReservationCollection reservationCollection = reservations as FileReservationCollection;

            if (reservationCollection == null || !reservationCollection.IsMyCollection(this))
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ArgumentInvalid(SR.LogRecSeq_InvalidReservationCollection));
            } 
 
            for (int i = 0; i < data.Count; i++)
            { 
                size += data[i].Count;
            }

            long reservation = reservationCollection.GetBestMatchingReservation(size); 

            if (reservation < 0) 
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ReservationNotFound());
            } 

            bool throwing = true;
            try
            { 
                SequenceNumber returnValue = this.Append(data, nextUndoRecord, previousRecord, recordAppendOptions);
                throwing = false; 
                return returnValue; 
            }
            finally 
            {
                if (throwing)
                {
                    reservationCollection.Add(reservation); 
                }
            } 
        } 

        public IAsyncResult BeginAppend( 
            ArraySegment data,
            SequenceNumber nextUndoRecord,
            SequenceNumber previousRecord,
            RecordAppendOptions recordAppendOptions, 
            AsyncCallback callback,
            object state) 
        { 
            return BeginAppend(new ArraySegment[] { data },
                               nextUndoRecord, 
                               previousRecord,
                               recordAppendOptions,
                               callback,
                               state); 
        }
 
 
        public IAsyncResult BeginAppend(
            ArraySegment data, 
            SequenceNumber nextUndoRecord,
            SequenceNumber previousRecord,
            RecordAppendOptions recordAppendOptions,
            ReservationCollection reservations, 
            AsyncCallback callback,
            object state) 
        { 
            return BeginAppend(new ArraySegment[] { data },
                               nextUndoRecord, 
                               previousRecord,
                               recordAppendOptions,
                               reservations,
                               callback, 
                               state);
        } 
 
        public IAsyncResult BeginAppend(
            IList> data, 
            SequenceNumber nextUndoRecord,
            SequenceNumber previousRecord,
            RecordAppendOptions recordAppendOptions,
            AsyncCallback callback, 
            object state)
        { 
            SequenceNumber result = Append(data, nextUndoRecord, previousRecord, recordAppendOptions); 
            return new FileRecordSequenceCompletedAsyncResult(result, callback, state, Work.Append);
        } 


        public IAsyncResult BeginAppend(
            IList> data, 
            SequenceNumber nextUndoRecord,
            SequenceNumber previousRecord, 
            RecordAppendOptions recordAppendOptions, 
            ReservationCollection reservations,
            AsyncCallback callback, 
            object state)
        {
            SequenceNumber result = Append(data, nextUndoRecord, previousRecord, recordAppendOptions, reservations);
            return new FileRecordSequenceCompletedAsyncResult(result, callback, state, Work.Append); 
        }
 
        public IAsyncResult BeginFlush( 
            SequenceNumber sequenceNumber,
            AsyncCallback callback, 
            object state)
        {
            SequenceNumber result = this.Flush(sequenceNumber);
            return new FileRecordSequenceCompletedAsyncResult(result, callback, state, Work.Flush); 
        }
 
        public IAsyncResult BeginReserveAndAppend( 
            ArraySegment data,
            SequenceNumber nextUndoRecord, 
            SequenceNumber previousRecord,
            RecordAppendOptions recordAppendOptions,
            ReservationCollection reservationCollection,
            long[] reservations, 
            AsyncCallback callback,
            object state) 
        { 
            return BeginReserveAndAppend(new ArraySegment[] { data },
                                         nextUndoRecord, 
                                         previousRecord,
                                         recordAppendOptions,
                                         reservationCollection,
                                         reservations, 
                                         callback,
                                         state); 
        } 

        public IAsyncResult BeginReserveAndAppend( 
            IList> data,
            SequenceNumber nextUndoRecord,
            SequenceNumber previousRecord,
            RecordAppendOptions recordAppendOptions, 
            ReservationCollection reservationCollection,
            long[] reservations, 
            AsyncCallback callback, 
            object state)
        { 
            SequenceNumber result = ReserveAndAppend( data,
                                                      nextUndoRecord,
                                                      previousRecord,
                                                      recordAppendOptions, 
                                                      reservationCollection,
                                                      reservations); 
 
            return new FileRecordSequenceCompletedAsyncResult(result, callback, state, Work.ReserveAndAppend);
        } 


        public IAsyncResult BeginWriteRestartArea(
            ArraySegment data, 
            SequenceNumber newBaseSeqNum,
            ReservationCollection reservation, 
            AsyncCallback callback, 
            object state)
        { 
            return BeginWriteRestartArea(new ArraySegment[] { data },
                                         newBaseSeqNum,
                                         reservation,
                                         callback, 
                                         state);
        } 
 
        public IAsyncResult BeginWriteRestartArea(
            IList> data, 
            SequenceNumber newBaseSeqNum,
            ReservationCollection reservation,
            AsyncCallback callback,
            object state) 
        {
            SequenceNumber result = WriteRestartArea(data, newBaseSeqNum, reservation); 
            return new FileRecordSequenceCompletedAsyncResult(result, callback, state, Work.WriteRestartArea); 
        }
 

        public ReservationCollection CreateReservationCollection()
        {
            FileReservationCollection collection = new FileReservationCollection(this); 
            return collection;
        } 
 

        public void Dispose() 
        {
            this.log.Close();
        }
 

        public SequenceNumber EndAppend( 
            IAsyncResult result) 
        {
            FileRecordSequenceCompletedAsyncResult asyncResult = result as FileRecordSequenceCompletedAsyncResult; 

            if (asyncResult == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ArgumentInvalid(SR.AsyncResult_Invalid)); 
            }
 
            if (asyncResult.CompletedWork != Work.Append) 
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ArgumentInvalid(SR.AsyncResult_Invalid)); 
            }

            return asyncResult.End();
        } 

 
        public SequenceNumber EndFlush( 
            IAsyncResult result)
        { 
            FileRecordSequenceCompletedAsyncResult asyncResult = result as FileRecordSequenceCompletedAsyncResult;

            if (asyncResult == null)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ArgumentInvalid(SR.AsyncResult_Invalid));
            } 
 
            if (asyncResult.CompletedWork != Work.Flush)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ArgumentInvalid(SR.AsyncResult_Invalid));
            }

            return asyncResult.End(); 
        }
 
        public SequenceNumber EndReserveAndAppend( 
            IAsyncResult result)
        { 
            FileRecordSequenceCompletedAsyncResult asyncResult = result as FileRecordSequenceCompletedAsyncResult;

            if (asyncResult == null)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ArgumentInvalid(SR.AsyncResult_Invalid));
            } 
 
            if (asyncResult.CompletedWork != Work.ReserveAndAppend)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ArgumentInvalid(SR.AsyncResult_Invalid));
            }

            return asyncResult.End(); 
        }
 
        public SequenceNumber EndWriteRestartArea( 
            IAsyncResult result)
        { 
            FileRecordSequenceCompletedAsyncResult asyncResult = result as FileRecordSequenceCompletedAsyncResult;

            if (asyncResult == null)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ArgumentInvalid(SR.AsyncResult_Invalid));
            } 
 
            if (asyncResult.CompletedWork != Work.WriteRestartArea)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ArgumentInvalid(SR.AsyncResult_Invalid));
            }

            return asyncResult.End(); 
        }
 
 
        public SequenceNumber Flush()
        { 
            return this.Flush(SequenceNumber.Invalid);
        }

 
        public SequenceNumber Flush(SequenceNumber sequenceNumber)
        { 
            return this.frsHelper.Flush(sequenceNumber); 
        }
 
        // The first thread raises the tail pinned event.
        // All other threads wait until first thread finishes.
        private void RaiseTailPinnedEvent()
        { 
            bool raiseEvent;
            Monitor.Enter(this.syncTailPinned); 
            try 
            {
                if (this.tailPinnedCalled) 
                {
                    if(this.tailPinnedThreadID == Thread.CurrentThread.ManagedThreadId)
                    {
                        // This is the same thread where RaiseTailPinnedEvent() was called and user 
                        // tried an Append or WriteRestartArea in the TailPinned callback.
                        // Let the first call complete... 
                        // Trying to prevent deadlock... 
                        return;
                    } 
                    else
                    {
                        // This is not the first thread.  Wait until the first thread has handled tail pinned
                        raiseEvent = false; 
                        Monitor.Wait(this.syncTailPinned);
                    } 
                } 
                else
                { 
                    // First thread.  Raise the event.
                    this.tailPinnedCalled = true;
                    raiseEvent = true;
                    this.tailPinnedThreadID = Thread.CurrentThread.ManagedThreadId; 
                }
            } 
            finally 
            {
                Monitor.Exit(this.syncTailPinned); 
            }

            if (raiseEvent)
            { 
                // First thread raises the event.  Signals other waiting threads when done.
                try 
                { 
                    EventHandler handler;
                    handler = this.TailPinned; 
                    if (handler != null)
                    {
                        try
                        { 
                            handler(this, new TailPinnedEventArgs(this.LastSequenceNumber));
                        } 
#pragma warning suppress 56500 // This is a callback exception 
                        catch (Exception exception)
                        { 
                            if (Fx.IsFatal(exception))
                                throw;

                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperCallback(exception); 
                        }
                    } 
                } 
                finally
                { 
                    Monitor.Enter(this.syncTailPinned);
                    try
                    {
                        this.tailPinnedCalled = false; 
                        this.tailPinnedThreadID = -1;
                        // Signal waiting threads 
                        Monitor.PulseAll(this.syncTailPinned); 
                    }
                    finally 
                    {
                        Monitor.Exit(this.syncTailPinned);
                    }
                } 
            }
        } 
 
        public IEnumerable ReadLogRecords(
            SequenceNumber start, 
            LogRecordEnumeratorType logRecordEnum)
        {
            if ((this.access & FileAccess.Read) == 0)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.NotSupported(SR.NotSupported_WriteOnly));
            } 
 
            if (logRecordEnum < LogRecordEnumeratorType.User || logRecordEnum > LogRecordEnumeratorType.Next)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ArgumentOutOfRange("logRecordEnum"));
            }

            return new FileLogRecordEnumerable(this.log, start, logRecordEnum, false); 
        }
 
 
        public IEnumerable ReadRestartAreas()
        { 
            if ((this.access & FileAccess.Read) == 0)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.NotSupported(SR.NotSupported_WriteOnly));
            } 

            return new FileLogRecordEnumerable( this.log, 
                                                this.frsHelper.RestartSequenceNumber, 
                                                LogRecordEnumeratorType.Previous,
                                                true); 
        }


        public SequenceNumber ReserveAndAppend( 
            ArraySegment data,
            SequenceNumber nextUndoRecord, 
            SequenceNumber previousRecord, 
            RecordAppendOptions recordAppendOptions,
            ReservationCollection reservationCollection, 
            params long[] reservations)
        {
            return ReserveAndAppend(new ArraySegment[] { data },
                                    nextUndoRecord, 
                                    previousRecord,
                                    recordAppendOptions, 
                                    reservationCollection, 
                                    reservations);
        } 

        public SequenceNumber ReserveAndAppend(
            IList> data,
            SequenceNumber nextUndoRecord, 
            SequenceNumber previousRecord,
            RecordAppendOptions recordAppendOptions, 
            ReservationCollection reservationCollection, 
            params long[] reservations)
        { 

            if (reservationCollection == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ArgumentNull("reservationCollection")); 
            }
 
            if (reservations == null) 
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ArgumentNull("reservations")); 
            }

            FileReservationCollection fileResCollection = null;
 
            fileResCollection = reservationCollection as FileReservationCollection;
            if (fileResCollection == null || !fileResCollection.IsMyCollection(this)) 
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ArgumentInvalid(SR.LogRecSeq_InvalidReservationCollection));
            } 

            foreach (long reservationSize in reservations)
            {
                if (reservationSize < 0) 
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ArgumentOutOfRange("reservations"));
            } 
 
            foreach (long reservationSize in reservations)
            { 
                fileResCollection.Add(reservationSize);
            }

            bool throwing = true; 
            try
            { 
                SequenceNumber returnValue = Append(data, nextUndoRecord, previousRecord, recordAppendOptions); 
                throwing = false;
                return returnValue; 
            }
            finally
            {
                if (throwing && fileResCollection != null) 
                {
                    foreach (long reservationSize in reservations) 
                    { 
                        fileResCollection.Remove(reservationSize);
                    } 
                }
            }
        }
 
        public SequenceNumber WriteRestartArea(
            ArraySegment data) 
        { 
            return WriteRestartArea(new ArraySegment[] { data });
        } 

        public SequenceNumber WriteRestartArea(
            ArraySegment data,
            SequenceNumber newBaseSeqNum) 
        {
            return WriteRestartArea(new ArraySegment[] { data }, 
                                    newBaseSeqNum); 
        }
 
        public SequenceNumber WriteRestartArea(
            ArraySegment data,
            SequenceNumber newBaseSeqNum,
            ReservationCollection reservations) 
        {
            return WriteRestartArea(new ArraySegment[] { data }, 
                                    newBaseSeqNum, 
                                    reservations);
        } 

        public SequenceNumber WriteRestartArea(
            IList> data)
        { 
            return WriteRestartArea(data, this.BaseSequenceNumber);
        } 
 
        public SequenceNumber WriteRestartArea(
            IList> data, 
            SequenceNumber newBaseSeqNum)
        {

           if(newBaseSeqNum == SequenceNumber.Invalid) 
           {
                newBaseSeqNum = this.BaseSequenceNumber; 
           } 

           try 
            {
                return this.frsHelper.WriteRestartAreaInternal(data, newBaseSeqNum);
            }
            catch (SequenceFullException) 
            {
                RaiseTailPinnedEvent(); 
 
                if (this.RetryAppend)
                { 
                    return this.frsHelper.WriteRestartAreaInternal(data, newBaseSeqNum);
                }
                else
                { 
                    throw;
                } 
            } 
        }
 

        public SequenceNumber WriteRestartArea(
            IList> data,
            SequenceNumber newBaseSeqNum, 
            ReservationCollection reservations)
        { 
            long size = 0; 

            if(data == null) 
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ArgumentNull("data"));
            }
 
            if (reservations == null)
                return WriteRestartArea(data, newBaseSeqNum); 
 
            FileReservationCollection reservationCollection = reservations as FileReservationCollection;
 
            if (reservationCollection == null || !reservationCollection.IsMyCollection(this))
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ArgumentInvalid(SR.LogRecSeq_InvalidReservationCollection));
            } 

            for (int i = 0; i < data.Count; i++) 
            { 
                size = checked(size + data[i].Count);
            } 
            long reservation = reservationCollection.GetBestMatchingReservation(size);

            if (reservation < 0)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ReservationNotFound());
            } 
 
            bool throwing = true;
            try 
            {
                SequenceNumber returnValue = WriteRestartArea(data, newBaseSeqNum);
                throwing = false;
                return returnValue; 
            }
            finally 
            { 
                if (throwing)
                { 
                    reservationCollection.Add(reservation);
                }
            }
        } 
    }
} 
 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------ 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------
namespace System.IO.Log
{ 
    using System;
    using System.Collections; 
    using System.Collections.Generic; 
    using System.IO;
    using System.Security.AccessControl; 
    using System.Runtime;
    using System.Runtime.InteropServices;
    using System.Security.Permissions;
    using System.Diagnostics; 
    using System.Threading;
 
    // FileRecordSequence uses Simple file log to write records to a file. 
    public sealed class FileRecordSequence : IRecordSequence
    { 
        SimpleFileLog log;
        bool retryAppend;
        object syncTailPinned = new object();
        bool tailPinnedCalled = false; 
        FileAccess access;
        FileRecordSequenceHelper frsHelper; 
        long reservedBytes; 
        object syncReservedBytes = new object();
        int tailPinnedThreadID = -1; 

        public FileRecordSequence(string path) : this(path, FileAccess.ReadWrite, 0) { }

        public FileRecordSequence(string path, FileAccess access) : this(path, access, 0) { } 

        [PermissionSetAttribute(SecurityAction.Demand, Name="FullTrust")] 
        public FileRecordSequence(string path, FileAccess access, int size) 
        {
            if (size < 0) 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ArgumentOutOfRange("size"));

            this.access = access;
            this.log = new SimpleFileLog(Path.GetFullPath(path), size); 
            this.frsHelper = new FileRecordSequenceHelper(this.log);
            this.reservedBytes = 0; 
        } 

        public SequenceNumber BaseSequenceNumber 
        {
            get { return this.frsHelper.BaseSequenceNumber; }
        }
 
        public SequenceNumber LastSequenceNumber
        { 
            get { return this.frsHelper.LastSequenceNumber; } 
        }
 
        public long MaximumRecordLength
        {
            get
            { 
                return Int32.MaxValue;
            } 
        } 

        public long ReservedBytes 
        {
            get
            {
                return this.reservedBytes; 
            }
        } 
 

        public bool RetryAppend 
        {
            get { return this.retryAppend; }
            set { this.retryAppend = value; }
        } 

 
        public SequenceNumber RestartSequenceNumber 
        {
            get { return this.frsHelper.RestartSequenceNumber; } 
        }

        public event EventHandler TailPinned;
 
        public void AdvanceBaseSequenceNumber(
            SequenceNumber newBaseSequenceNumber) 
        { 
            this.frsHelper.AdvanceBaseSequeceNumber(newBaseSequenceNumber);
        } 

        internal void AddReservation(long reservation)
        {
            lock (this.syncReservedBytes) 
            {
                this.reservedBytes += reservation; 
            } 
        }
 
        internal void RemoveReservation(long reservation)
        {
            lock (this.syncReservedBytes)
            { 
                this.reservedBytes -= reservation;
            } 
        } 

        public SequenceNumber Append( 
            ArraySegment data,
            SequenceNumber nextUndoRecord,
            SequenceNumber previousRecord,
            RecordAppendOptions recordAppendOptions) 
        {
            return Append(new ArraySegment[] { data }, 
                          nextUndoRecord, 
                          previousRecord,
                          recordAppendOptions); 
        }

        public SequenceNumber Append(
            ArraySegment data, 
            SequenceNumber nextUndoRecord,
            SequenceNumber previousRecord, 
            RecordAppendOptions recordAppendOptions, 
            ReservationCollection reservations)
        { 
            return Append(new ArraySegment[] { data },
                          nextUndoRecord,
                          previousRecord,
                          recordAppendOptions, 
                          reservations);
        } 
 
        public SequenceNumber Append(
            IList> data, 
            SequenceNumber nextUndoRecord,
            SequenceNumber previousRecord,
            RecordAppendOptions recordAppendOptions)
        { 
            if (data == null)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ArgumentNull("data")); 
            }
 
            if ((this.access & FileAccess.Write) == 0)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.NotSupported(SR.NotSupported_ReadOnly));
            } 

            if(recordAppendOptions > (RecordAppendOptions.ForceAppend | RecordAppendOptions.ForceFlush) || 
               recordAppendOptions < RecordAppendOptions.None) 
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ArgumentOutOfRange("recordAppendOptions")); 
            }

            SequenceNumber sn;
            bool forceFlush = (recordAppendOptions & RecordAppendOptions.ForceFlush) != 0; 
            try
            { 
                sn = frsHelper.Append(data, nextUndoRecord, previousRecord, forceFlush); 
            }
            catch (SequenceFullException) 
            {
                RaiseTailPinnedEvent();

                if (this.RetryAppend) 
                {
                    sn = frsHelper.Append(data, nextUndoRecord, previousRecord, forceFlush); 
                } 
                else
                { 
                    throw;
                }
            }
 
            return sn;
        } 
 

        public SequenceNumber Append( 
            IList> data,
            SequenceNumber nextUndoRecord,
            SequenceNumber previousRecord,
            RecordAppendOptions recordAppendOptions, 
            ReservationCollection reservations)
        { 
            int size = 0; 

            if (reservations == null) 
            {
                return Append(data, nextUndoRecord, previousRecord, recordAppendOptions);
            }
 
            if (data == null)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ArgumentNull("data")); 
            }
 
            FileReservationCollection reservationCollection = reservations as FileReservationCollection;

            if (reservationCollection == null || !reservationCollection.IsMyCollection(this))
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ArgumentInvalid(SR.LogRecSeq_InvalidReservationCollection));
            } 
 
            for (int i = 0; i < data.Count; i++)
            { 
                size += data[i].Count;
            }

            long reservation = reservationCollection.GetBestMatchingReservation(size); 

            if (reservation < 0) 
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ReservationNotFound());
            } 

            bool throwing = true;
            try
            { 
                SequenceNumber returnValue = this.Append(data, nextUndoRecord, previousRecord, recordAppendOptions);
                throwing = false; 
                return returnValue; 
            }
            finally 
            {
                if (throwing)
                {
                    reservationCollection.Add(reservation); 
                }
            } 
        } 

        public IAsyncResult BeginAppend( 
            ArraySegment data,
            SequenceNumber nextUndoRecord,
            SequenceNumber previousRecord,
            RecordAppendOptions recordAppendOptions, 
            AsyncCallback callback,
            object state) 
        { 
            return BeginAppend(new ArraySegment[] { data },
                               nextUndoRecord, 
                               previousRecord,
                               recordAppendOptions,
                               callback,
                               state); 
        }
 
 
        public IAsyncResult BeginAppend(
            ArraySegment data, 
            SequenceNumber nextUndoRecord,
            SequenceNumber previousRecord,
            RecordAppendOptions recordAppendOptions,
            ReservationCollection reservations, 
            AsyncCallback callback,
            object state) 
        { 
            return BeginAppend(new ArraySegment[] { data },
                               nextUndoRecord, 
                               previousRecord,
                               recordAppendOptions,
                               reservations,
                               callback, 
                               state);
        } 
 
        public IAsyncResult BeginAppend(
            IList> data, 
            SequenceNumber nextUndoRecord,
            SequenceNumber previousRecord,
            RecordAppendOptions recordAppendOptions,
            AsyncCallback callback, 
            object state)
        { 
            SequenceNumber result = Append(data, nextUndoRecord, previousRecord, recordAppendOptions); 
            return new FileRecordSequenceCompletedAsyncResult(result, callback, state, Work.Append);
        } 


        public IAsyncResult BeginAppend(
            IList> data, 
            SequenceNumber nextUndoRecord,
            SequenceNumber previousRecord, 
            RecordAppendOptions recordAppendOptions, 
            ReservationCollection reservations,
            AsyncCallback callback, 
            object state)
        {
            SequenceNumber result = Append(data, nextUndoRecord, previousRecord, recordAppendOptions, reservations);
            return new FileRecordSequenceCompletedAsyncResult(result, callback, state, Work.Append); 
        }
 
        public IAsyncResult BeginFlush( 
            SequenceNumber sequenceNumber,
            AsyncCallback callback, 
            object state)
        {
            SequenceNumber result = this.Flush(sequenceNumber);
            return new FileRecordSequenceCompletedAsyncResult(result, callback, state, Work.Flush); 
        }
 
        public IAsyncResult BeginReserveAndAppend( 
            ArraySegment data,
            SequenceNumber nextUndoRecord, 
            SequenceNumber previousRecord,
            RecordAppendOptions recordAppendOptions,
            ReservationCollection reservationCollection,
            long[] reservations, 
            AsyncCallback callback,
            object state) 
        { 
            return BeginReserveAndAppend(new ArraySegment[] { data },
                                         nextUndoRecord, 
                                         previousRecord,
                                         recordAppendOptions,
                                         reservationCollection,
                                         reservations, 
                                         callback,
                                         state); 
        } 

        public IAsyncResult BeginReserveAndAppend( 
            IList> data,
            SequenceNumber nextUndoRecord,
            SequenceNumber previousRecord,
            RecordAppendOptions recordAppendOptions, 
            ReservationCollection reservationCollection,
            long[] reservations, 
            AsyncCallback callback, 
            object state)
        { 
            SequenceNumber result = ReserveAndAppend( data,
                                                      nextUndoRecord,
                                                      previousRecord,
                                                      recordAppendOptions, 
                                                      reservationCollection,
                                                      reservations); 
 
            return new FileRecordSequenceCompletedAsyncResult(result, callback, state, Work.ReserveAndAppend);
        } 


        public IAsyncResult BeginWriteRestartArea(
            ArraySegment data, 
            SequenceNumber newBaseSeqNum,
            ReservationCollection reservation, 
            AsyncCallback callback, 
            object state)
        { 
            return BeginWriteRestartArea(new ArraySegment[] { data },
                                         newBaseSeqNum,
                                         reservation,
                                         callback, 
                                         state);
        } 
 
        public IAsyncResult BeginWriteRestartArea(
            IList> data, 
            SequenceNumber newBaseSeqNum,
            ReservationCollection reservation,
            AsyncCallback callback,
            object state) 
        {
            SequenceNumber result = WriteRestartArea(data, newBaseSeqNum, reservation); 
            return new FileRecordSequenceCompletedAsyncResult(result, callback, state, Work.WriteRestartArea); 
        }
 

        public ReservationCollection CreateReservationCollection()
        {
            FileReservationCollection collection = new FileReservationCollection(this); 
            return collection;
        } 
 

        public void Dispose() 
        {
            this.log.Close();
        }
 

        public SequenceNumber EndAppend( 
            IAsyncResult result) 
        {
            FileRecordSequenceCompletedAsyncResult asyncResult = result as FileRecordSequenceCompletedAsyncResult; 

            if (asyncResult == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ArgumentInvalid(SR.AsyncResult_Invalid)); 
            }
 
            if (asyncResult.CompletedWork != Work.Append) 
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ArgumentInvalid(SR.AsyncResult_Invalid)); 
            }

            return asyncResult.End();
        } 

 
        public SequenceNumber EndFlush( 
            IAsyncResult result)
        { 
            FileRecordSequenceCompletedAsyncResult asyncResult = result as FileRecordSequenceCompletedAsyncResult;

            if (asyncResult == null)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ArgumentInvalid(SR.AsyncResult_Invalid));
            } 
 
            if (asyncResult.CompletedWork != Work.Flush)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ArgumentInvalid(SR.AsyncResult_Invalid));
            }

            return asyncResult.End(); 
        }
 
        public SequenceNumber EndReserveAndAppend( 
            IAsyncResult result)
        { 
            FileRecordSequenceCompletedAsyncResult asyncResult = result as FileRecordSequenceCompletedAsyncResult;

            if (asyncResult == null)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ArgumentInvalid(SR.AsyncResult_Invalid));
            } 
 
            if (asyncResult.CompletedWork != Work.ReserveAndAppend)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ArgumentInvalid(SR.AsyncResult_Invalid));
            }

            return asyncResult.End(); 
        }
 
        public SequenceNumber EndWriteRestartArea( 
            IAsyncResult result)
        { 
            FileRecordSequenceCompletedAsyncResult asyncResult = result as FileRecordSequenceCompletedAsyncResult;

            if (asyncResult == null)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ArgumentInvalid(SR.AsyncResult_Invalid));
            } 
 
            if (asyncResult.CompletedWork != Work.WriteRestartArea)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ArgumentInvalid(SR.AsyncResult_Invalid));
            }

            return asyncResult.End(); 
        }
 
 
        public SequenceNumber Flush()
        { 
            return this.Flush(SequenceNumber.Invalid);
        }

 
        public SequenceNumber Flush(SequenceNumber sequenceNumber)
        { 
            return this.frsHelper.Flush(sequenceNumber); 
        }
 
        // The first thread raises the tail pinned event.
        // All other threads wait until first thread finishes.
        private void RaiseTailPinnedEvent()
        { 
            bool raiseEvent;
            Monitor.Enter(this.syncTailPinned); 
            try 
            {
                if (this.tailPinnedCalled) 
                {
                    if(this.tailPinnedThreadID == Thread.CurrentThread.ManagedThreadId)
                    {
                        // This is the same thread where RaiseTailPinnedEvent() was called and user 
                        // tried an Append or WriteRestartArea in the TailPinned callback.
                        // Let the first call complete... 
                        // Trying to prevent deadlock... 
                        return;
                    } 
                    else
                    {
                        // This is not the first thread.  Wait until the first thread has handled tail pinned
                        raiseEvent = false; 
                        Monitor.Wait(this.syncTailPinned);
                    } 
                } 
                else
                { 
                    // First thread.  Raise the event.
                    this.tailPinnedCalled = true;
                    raiseEvent = true;
                    this.tailPinnedThreadID = Thread.CurrentThread.ManagedThreadId; 
                }
            } 
            finally 
            {
                Monitor.Exit(this.syncTailPinned); 
            }

            if (raiseEvent)
            { 
                // First thread raises the event.  Signals other waiting threads when done.
                try 
                { 
                    EventHandler handler;
                    handler = this.TailPinned; 
                    if (handler != null)
                    {
                        try
                        { 
                            handler(this, new TailPinnedEventArgs(this.LastSequenceNumber));
                        } 
#pragma warning suppress 56500 // This is a callback exception 
                        catch (Exception exception)
                        { 
                            if (Fx.IsFatal(exception))
                                throw;

                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperCallback(exception); 
                        }
                    } 
                } 
                finally
                { 
                    Monitor.Enter(this.syncTailPinned);
                    try
                    {
                        this.tailPinnedCalled = false; 
                        this.tailPinnedThreadID = -1;
                        // Signal waiting threads 
                        Monitor.PulseAll(this.syncTailPinned); 
                    }
                    finally 
                    {
                        Monitor.Exit(this.syncTailPinned);
                    }
                } 
            }
        } 
 
        public IEnumerable ReadLogRecords(
            SequenceNumber start, 
            LogRecordEnumeratorType logRecordEnum)
        {
            if ((this.access & FileAccess.Read) == 0)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.NotSupported(SR.NotSupported_WriteOnly));
            } 
 
            if (logRecordEnum < LogRecordEnumeratorType.User || logRecordEnum > LogRecordEnumeratorType.Next)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ArgumentOutOfRange("logRecordEnum"));
            }

            return new FileLogRecordEnumerable(this.log, start, logRecordEnum, false); 
        }
 
 
        public IEnumerable ReadRestartAreas()
        { 
            if ((this.access & FileAccess.Read) == 0)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.NotSupported(SR.NotSupported_WriteOnly));
            } 

            return new FileLogRecordEnumerable( this.log, 
                                                this.frsHelper.RestartSequenceNumber, 
                                                LogRecordEnumeratorType.Previous,
                                                true); 
        }


        public SequenceNumber ReserveAndAppend( 
            ArraySegment data,
            SequenceNumber nextUndoRecord, 
            SequenceNumber previousRecord, 
            RecordAppendOptions recordAppendOptions,
            ReservationCollection reservationCollection, 
            params long[] reservations)
        {
            return ReserveAndAppend(new ArraySegment[] { data },
                                    nextUndoRecord, 
                                    previousRecord,
                                    recordAppendOptions, 
                                    reservationCollection, 
                                    reservations);
        } 

        public SequenceNumber ReserveAndAppend(
            IList> data,
            SequenceNumber nextUndoRecord, 
            SequenceNumber previousRecord,
            RecordAppendOptions recordAppendOptions, 
            ReservationCollection reservationCollection, 
            params long[] reservations)
        { 

            if (reservationCollection == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ArgumentNull("reservationCollection")); 
            }
 
            if (reservations == null) 
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ArgumentNull("reservations")); 
            }

            FileReservationCollection fileResCollection = null;
 
            fileResCollection = reservationCollection as FileReservationCollection;
            if (fileResCollection == null || !fileResCollection.IsMyCollection(this)) 
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ArgumentInvalid(SR.LogRecSeq_InvalidReservationCollection));
            } 

            foreach (long reservationSize in reservations)
            {
                if (reservationSize < 0) 
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ArgumentOutOfRange("reservations"));
            } 
 
            foreach (long reservationSize in reservations)
            { 
                fileResCollection.Add(reservationSize);
            }

            bool throwing = true; 
            try
            { 
                SequenceNumber returnValue = Append(data, nextUndoRecord, previousRecord, recordAppendOptions); 
                throwing = false;
                return returnValue; 
            }
            finally
            {
                if (throwing && fileResCollection != null) 
                {
                    foreach (long reservationSize in reservations) 
                    { 
                        fileResCollection.Remove(reservationSize);
                    } 
                }
            }
        }
 
        public SequenceNumber WriteRestartArea(
            ArraySegment data) 
        { 
            return WriteRestartArea(new ArraySegment[] { data });
        } 

        public SequenceNumber WriteRestartArea(
            ArraySegment data,
            SequenceNumber newBaseSeqNum) 
        {
            return WriteRestartArea(new ArraySegment[] { data }, 
                                    newBaseSeqNum); 
        }
 
        public SequenceNumber WriteRestartArea(
            ArraySegment data,
            SequenceNumber newBaseSeqNum,
            ReservationCollection reservations) 
        {
            return WriteRestartArea(new ArraySegment[] { data }, 
                                    newBaseSeqNum, 
                                    reservations);
        } 

        public SequenceNumber WriteRestartArea(
            IList> data)
        { 
            return WriteRestartArea(data, this.BaseSequenceNumber);
        } 
 
        public SequenceNumber WriteRestartArea(
            IList> data, 
            SequenceNumber newBaseSeqNum)
        {

           if(newBaseSeqNum == SequenceNumber.Invalid) 
           {
                newBaseSeqNum = this.BaseSequenceNumber; 
           } 

           try 
            {
                return this.frsHelper.WriteRestartAreaInternal(data, newBaseSeqNum);
            }
            catch (SequenceFullException) 
            {
                RaiseTailPinnedEvent(); 
 
                if (this.RetryAppend)
                { 
                    return this.frsHelper.WriteRestartAreaInternal(data, newBaseSeqNum);
                }
                else
                { 
                    throw;
                } 
            } 
        }
 

        public SequenceNumber WriteRestartArea(
            IList> data,
            SequenceNumber newBaseSeqNum, 
            ReservationCollection reservations)
        { 
            long size = 0; 

            if(data == null) 
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ArgumentNull("data"));
            }
 
            if (reservations == null)
                return WriteRestartArea(data, newBaseSeqNum); 
 
            FileReservationCollection reservationCollection = reservations as FileReservationCollection;
 
            if (reservationCollection == null || !reservationCollection.IsMyCollection(this))
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ArgumentInvalid(SR.LogRecSeq_InvalidReservationCollection));
            } 

            for (int i = 0; i < data.Count; i++) 
            { 
                size = checked(size + data[i].Count);
            } 
            long reservation = reservationCollection.GetBestMatchingReservation(size);

            if (reservation < 0)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ReservationNotFound());
            } 
 
            bool throwing = true;
            try 
            {
                SequenceNumber returnValue = WriteRestartArea(data, newBaseSeqNum);
                throwing = false;
                return returnValue; 
            }
            finally 
            { 
                if (throwing)
                { 
                    reservationCollection.Add(reservation);
                }
            }
        } 
    }
} 
 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK