Code:
/ WCF / WCF / 3.5.30729.1 / untmp / Orcas / SP / ndp / cdf / src / WCF / Log / System / IO / Log / FileRecordSequenceHelper.cs / 1 / FileRecordSequenceHelper.cs
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------
using System;
using System.Threading;
using System.Collections.Generic;
namespace System.IO.Log
{
// This class contains all the workarounds for simple file log.
internal class FileRecordSequenceHelper
{
SimpleFileLog log;
SequenceNumber newBaseSeqNum;
SequenceNumber lastRestartArea;
// We take a reader lock during append and a writer lock during WriteRestartArea and Truncate.
ReaderWriterLock appendLock;
// We need to handle truncate failure during Recover otherwise the user will not be able to open the log.
// If truncate fails, all operations except 'Read' retry trucate.
bool truncateFailed;
internal FileRecordSequenceHelper(SimpleFileLog log)
{
this.log = log;
this.appendLock = new ReaderWriterLock();
this.truncateFailed = false;
this.lastRestartArea = SequenceNumber.Invalid;
this.newBaseSeqNum = SequenceNumber.Invalid;
Recover();
}
internal SequenceNumber BaseSequenceNumber
{
get
{
SequenceNumber first, last;
this.log.GetLogLimits(out first, out last);
return first;
}
}
internal SequenceNumber LastSequenceNumber
{
get
{
SequenceNumber first, last;
log.GetLogLimits(out first, out last);
if (last != SequenceNumber.Invalid)
{
if (last < first)
{
// Special condition - log empty.
// When the last sequence number returned by simple file log is less than the first,
// the log is empty.
// For IO.Log OM, if log is empty then Base lsn == Last lsn.
return new SequenceNumber(first.High, 0);
}
else
{
// The low part is 1 because the last sequence number should be greater than
// the sequence number of the last record in the log.
// Last sequence number is a valid input only to WriteRestartArea.
return new SequenceNumber(last.High, 1);
}
}
else
{
return last;
}
}
}
internal SequenceNumber RestartSequenceNumber
{
get { return this.lastRestartArea; }
}
// 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 (DiagnosticUtility.IsFatal(exception)) throw;
}
}
}
break;
}
sn = stream.PrevLsn;
}
}
internal void ValidateSequenceNumber(SequenceNumber sequenceNumber)
{
if (sequenceNumber == SequenceNumber.Invalid || sequenceNumber.Low != 0)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.SequenceNumberInvalid());
}
if (sequenceNumber < this.BaseSequenceNumber || sequenceNumber > this.LastSequenceNumber)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.SequenceNumberNotActive("sequenceNumber"));
}
}
internal void AdvanceBaseSequeceNumber(SequenceNumber newBaseSequenceNumber)
{
TruncateIfNecessary();
bool lockHeld = false;
try
{
try { }
finally
{
appendLock.AcquireWriterLock(-1);
lockHeld = true;
}
ValidateSequenceNumber(newBaseSequenceNumber);
this.log.TruncatePrefix(newBaseSequenceNumber);
}
finally
{
if (lockHeld)
{
appendLock.ReleaseWriterLock();
}
}
}
internal SequenceNumber Append( IList> data,
SequenceNumber nextUndoRecord,
SequenceNumber previousRecord,
bool forceFlush)
{
TruncateIfNecessary();
bool lockHeld = false;
try
{
try { }
finally
{
appendLock.AcquireReaderLock(-1);
lockHeld = true;
}
using (AppendHelper helper = new AppendHelper(
data,
previousRecord,
nextUndoRecord,
false))
{
return log.AppendRecord(helper.Blobs, forceFlush);
}
}
finally
{
if (lockHeld)
{
appendLock.ReleaseReaderLock();
}
}
}
internal SequenceNumber Flush(SequenceNumber sequenceNumber)
{
TruncateIfNecessary();
if (sequenceNumber == SequenceNumber.Invalid)
{
// Re-interpret... SimpleFileLog uses 0 to mean "flush
// entire log", not SequenceNumber.Invalid.
//
sequenceNumber = new SequenceNumber(0);
}
else
{
ValidateSequenceNumber(sequenceNumber);
}
this.log.Force(sequenceNumber);
return sequenceNumber;
}
internal SequenceNumber WriteRestartAreaInternal(
IList> data,
SequenceNumber newBaseSeqNum)
{
if(data == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ArgumentNull("data"));
}
TruncateIfNecessary();
bool lockHeld = false;
try
{
try { }
finally
{
appendLock.AcquireWriterLock(-1);
lockHeld = true;
}
SequenceNumber sn;
AppendHelper helper;
bool lastSeqNum, firstSeqNum;
lastSeqNum = newBaseSeqNum == this.LastSequenceNumber;
firstSeqNum = newBaseSeqNum == this.BaseSequenceNumber;
if (lastSeqNum)
{
// We dont know the new base sequence number.
// It will be the sequence number we get from append.
helper = new AppendHelper(data,
this.lastRestartArea,
SequenceNumber.Invalid,
true);
}
else
{
if(!firstSeqNum)
{
ValidateSequenceNumber(newBaseSeqNum);
// Validate newBaseSequenceNumber by reading the corresponding record.
int cbData = 1;
byte[] record;
int recordSize;
SequenceNumber prev, next;
// Sequence number validation checks if the Seq Num > BSN and Seq Num < LSN.
// Now we validate if Seq Number is a valid number in this sequence.
try
{
this.log.ReadRecordPrefix(newBaseSeqNum, out record, ref cbData, out recordSize, out prev, out next);
}
catch(ArgumentException exception)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Error.ArgumentOutOfRange(SR.Argument_TailInvalid, exception));
}
}
helper = new AppendHelper(data,
this.lastRestartArea,
newBaseSeqNum,
true);
}
// If there is a failure betweeen append and truncate,
// then the log will be in an inconsistent state. To
// solve this, we write the new base sequence number in
// the header. During recovery from failure, we will find
// the restart area and truncate the log.
using (helper)
{
// No need for a reader appendLock, since WriteRestartAreaInternal is under a lock.
sn = this.log.AppendRecord(helper.Blobs, true);
}
this.lastRestartArea = sn;
if(firstSeqNum)
{
return sn;
}
if (lastSeqNum)
{
newBaseSeqNum = sn;
}
try
{
log.TruncatePrefix(newBaseSeqNum);
}
#pragma warning suppress 56500
catch (Exception exception)
{
this.newBaseSeqNum = newBaseSeqNum;
this.truncateFailed = true;
if (DiagnosticUtility.IsFatal(exception)) throw;
}
return sn;
}
finally
{
if (lockHeld)
{
appendLock.ReleaseWriterLock();
}
}
}
private void TruncateIfNecessary()
{
// Retry trucate if it failed during Recover or WriteRestartArea.
if (this.truncateFailed)
{
bool lockHeld = false;
try
{
try { }
finally
{
appendLock.AcquireWriterLock(-1);
lockHeld = true;
}
if (this.truncateFailed)
{
this.log.TruncatePrefix(this.newBaseSeqNum);
this.truncateFailed = false;
}
}
finally
{
if (lockHeld)
{
appendLock.ReleaseWriterLock();
}
}
}
}
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- InternalTypeHelper.cs
- DataGridColumnCollection.cs
- ToolStripDropDownClosingEventArgs.cs
- BasePropertyDescriptor.cs
- DiscoveryMessageProperty.cs
- ObjectDataSourceFilteringEventArgs.cs
- InstanceContextManager.cs
- XmlWrappingReader.cs
- DATA_BLOB.cs
- ErrorFormatterPage.cs
- InplaceBitmapMetadataWriter.cs
- WmfPlaceableFileHeader.cs
- TransformerInfo.cs
- MoveSizeWinEventHandler.cs
- HierarchicalDataSourceControl.cs
- RSAPKCS1SignatureDeformatter.cs
- ProcessHostConfigUtils.cs
- TableSectionStyle.cs
- BaseCollection.cs
- CallbackHandler.cs
- XmlBinaryReader.cs
- SynchronizationContext.cs
- Errors.cs
- ServicePerformanceCounters.cs
- BamlLocalizerErrorNotifyEventArgs.cs
- GroupBoxAutomationPeer.cs
- Substitution.cs
- PreservationFileWriter.cs
- SHA1CryptoServiceProvider.cs
- PopupRoot.cs
- RSAPKCS1SignatureDeformatter.cs
- AttributeUsageAttribute.cs
- ScrollEventArgs.cs
- OciEnlistContext.cs
- WorkflowPersistenceService.cs
- XamlReaderConstants.cs
- DataGridHeaderBorder.cs
- Stylus.cs
- XmlValueConverter.cs
- QilBinary.cs
- ObjectDataSourceMethodEventArgs.cs
- httpstaticobjectscollection.cs
- Model3DGroup.cs
- EdmTypeAttribute.cs
- Win32.cs
- RangeContentEnumerator.cs
- TemplatedWizardStep.cs
- UnknownWrapper.cs
- ExponentialEase.cs
- WebEvents.cs
- ColumnBinding.cs
- VerticalConnector.xaml.cs
- EdgeModeValidation.cs
- BookmarkScope.cs
- OracleLob.cs
- AsyncCompletedEventArgs.cs
- ResourceDictionary.cs
- TraceListener.cs
- SessionEndingCancelEventArgs.cs
- _SSPISessionCache.cs
- KnownIds.cs
- CellLabel.cs
- CollectionBuilder.cs
- RuntimeArgument.cs
- CodeBinaryOperatorExpression.cs
- ProcessThreadDesigner.cs
- WorkflowApplicationUnloadedException.cs
- HideDisabledControlAdapter.cs
- IntegerValidatorAttribute.cs
- SQLCharsStorage.cs
- FrameworkElementAutomationPeer.cs
- DynamicActivityProperty.cs
- XsltArgumentList.cs
- TypeReference.cs
- SelectionEditor.cs
- ThreadStateException.cs
- SHA384.cs
- TraceLevelStore.cs
- LoginView.cs
- CryptoApi.cs
- StateFinalizationDesigner.cs
- TraceListeners.cs
- RelatedCurrencyManager.cs
- HScrollProperties.cs
- CompiledQuery.cs
- SecurityVerifiedMessage.cs
- ConfigurationSchemaErrors.cs
- PropertyEmitterBase.cs
- Debug.cs
- AnonymousIdentificationModule.cs
- ArglessEventHandlerProxy.cs
- ObjectDataSourceFilteringEventArgs.cs
- ToolStripPanelCell.cs
- ToolStripPanelRow.cs
- SymbolPair.cs
- OrderByLifter.cs
- TreePrinter.cs
- LinkLabelLinkClickedEvent.cs
- ListBindingConverter.cs
- listviewsubitemcollectioneditor.cs