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
- ContentPropertyAttribute.cs
- HttpInputStream.cs
- Collection.cs
- DynamicEndpoint.cs
- LambdaCompiler.Logical.cs
- CodeNamespaceImport.cs
- AssemblyGen.cs
- StrongNameIdentityPermission.cs
- ZoneIdentityPermission.cs
- RealProxy.cs
- StretchValidation.cs
- ComponentResourceKeyConverter.cs
- WebPartTracker.cs
- MemberAssignment.cs
- Speller.cs
- LateBoundBitmapDecoder.cs
- httpserverutility.cs
- TimeSpanValidator.cs
- XslCompiledTransform.cs
- ProfileManager.cs
- CacheRequest.cs
- StringWriter.cs
- ClientCultureInfo.cs
- NamespaceCollection.cs
- OracleRowUpdatedEventArgs.cs
- LocalIdKeyIdentifierClause.cs
- PersonalizationEntry.cs
- ReflectionTypeLoadException.cs
- TransactionManager.cs
- ManipulationStartedEventArgs.cs
- GeneralTransformCollection.cs
- DeflateStream.cs
- ExclusiveHandleList.cs
- _OverlappedAsyncResult.cs
- CompModSwitches.cs
- WindowsFormsHostAutomationPeer.cs
- CodeTypeMemberCollection.cs
- CodeGotoStatement.cs
- ItemChangedEventArgs.cs
- MappingModelBuildProvider.cs
- SubtreeProcessor.cs
- DataGridViewCellConverter.cs
- SafeLibraryHandle.cs
- MembershipValidatePasswordEventArgs.cs
- HttpVersion.cs
- FileLevelControlBuilderAttribute.cs
- FileSystemInfo.cs
- brushes.cs
- StreamHelper.cs
- ArgumentOutOfRangeException.cs
- SurrogateEncoder.cs
- GenericRootAutomationPeer.cs
- DesignerActionListCollection.cs
- StackBuilderSink.cs
- WebPartDeleteVerb.cs
- Propagator.JoinPropagator.cs
- EventListenerClientSide.cs
- WriteableBitmap.cs
- backend.cs
- InternalBufferManager.cs
- MetafileHeader.cs
- CultureTable.cs
- InsufficientMemoryException.cs
- SemaphoreFullException.cs
- BoundField.cs
- SmtpNetworkElement.cs
- SelectedDatesCollection.cs
- Resources.Designer.cs
- AutomationPattern.cs
- EventOpcode.cs
- BaseDataListComponentEditor.cs
- QueryOutputWriterV1.cs
- BitmapEffectrendercontext.cs
- VarRemapper.cs
- XsdSchemaFileEditor.cs
- RegistryDataKey.cs
- TreeViewCancelEvent.cs
- LicenseException.cs
- ErrorHandler.cs
- LightweightCodeGenerator.cs
- EllipticalNodeOperations.cs
- GlyphElement.cs
- BuildResult.cs
- StreamGeometry.cs
- XsltSettings.cs
- XmlSchemaAny.cs
- Canvas.cs
- SqlMethods.cs
- SharedStream.cs
- SetterTriggerConditionValueConverter.cs
- TextTreeExtractElementUndoUnit.cs
- PropertyValue.cs
- ProgressBarBrushConverter.cs
- base64Transforms.cs
- SafeArrayRankMismatchException.cs
- ScrollProviderWrapper.cs
- SQLByte.cs
- Line.cs
- RenderOptions.cs
- FixedTextBuilder.cs