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
- BinaryObjectReader.cs
- TextLine.cs
- MetadataArtifactLoaderComposite.cs
- ViewStateException.cs
- WindowsToolbar.cs
- StyleBamlRecordReader.cs
- ButtonStandardAdapter.cs
- VirtualPath.cs
- LineProperties.cs
- AuthenticationException.cs
- DataQuery.cs
- SizeChangedEventArgs.cs
- Timeline.cs
- FrameworkTextComposition.cs
- StoryFragments.cs
- SqlDataRecord.cs
- JournalEntry.cs
- CompositeCollectionView.cs
- CompiledQueryCacheEntry.cs
- WebServiceAttribute.cs
- ColorPalette.cs
- RewritingProcessor.cs
- WindowsComboBox.cs
- SqlConnectionStringBuilder.cs
- NumericUpDownAccelerationCollection.cs
- DbDeleteCommandTree.cs
- PageCodeDomTreeGenerator.cs
- FixedBufferAttribute.cs
- TextServicesCompartment.cs
- SqlGenerator.cs
- Byte.cs
- SoundPlayerAction.cs
- AssemblyCache.cs
- XhtmlTextWriter.cs
- NumberAction.cs
- TempEnvironment.cs
- RectangleConverter.cs
- MailWebEventProvider.cs
- PeerCustomResolverSettings.cs
- HostExecutionContextManager.cs
- InfoCardServiceInstallComponent.cs
- FontNamesConverter.cs
- NumberFormatInfo.cs
- ServiceReference.cs
- StackSpiller.Bindings.cs
- AsymmetricKeyExchangeFormatter.cs
- BitmapEffectDrawing.cs
- ColumnMapCopier.cs
- Pkcs7Recipient.cs
- DataGridViewColumnEventArgs.cs
- CalendarDesigner.cs
- JumpTask.cs
- CompositionTarget.cs
- CompiledQueryCacheEntry.cs
- KeyboardDevice.cs
- EntityDataSourceWizardForm.cs
- DetailsViewPageEventArgs.cs
- _SslSessionsCache.cs
- MethodBody.cs
- DBNull.cs
- ColorKeyFrameCollection.cs
- CodeGroup.cs
- PropertyGrid.cs
- ManagedIStream.cs
- StructuralObject.cs
- SerializationUtility.cs
- connectionpool.cs
- ControlTemplate.cs
- MethodInfo.cs
- ProxyElement.cs
- UInt32Converter.cs
- GiveFeedbackEventArgs.cs
- SqlUnionizer.cs
- PerspectiveCamera.cs
- OperationAbortedException.cs
- IntSecurity.cs
- WebReference.cs
- HttpProfileBase.cs
- CaseStatementSlot.cs
- ConfigurationProperty.cs
- MatrixUtil.cs
- ConfigUtil.cs
- ExtendedProtectionPolicy.cs
- CLSCompliantAttribute.cs
- TextShapeableCharacters.cs
- ToolBarOverflowPanel.cs
- EventListener.cs
- WinHttpWebProxyFinder.cs
- HorizontalAlignConverter.cs
- LabelEditEvent.cs
- XmlAttributeCollection.cs
- ObjectStorage.cs
- CellParagraph.cs
- EnumerableCollectionView.cs
- CallbackHandler.cs
- DataGridViewCellConverter.cs
- FixedSOMTextRun.cs
- DoubleCollectionValueSerializer.cs
- Identity.cs
- ControlPropertyNameConverter.cs