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
- ThousandthOfEmRealDoubles.cs
- RuleSettings.cs
- ControlCachePolicy.cs
- RSAPKCS1KeyExchangeDeformatter.cs
- DataGridSortCommandEventArgs.cs
- HttpPostServerProtocol.cs
- SkewTransform.cs
- ConsumerConnectionPoint.cs
- RuntimeHandles.cs
- DataListItemEventArgs.cs
- ColumnWidthChangingEvent.cs
- WeakReadOnlyCollection.cs
- ReadOnlyTernaryTree.cs
- Attributes.cs
- XamlTypeMapper.cs
- ElapsedEventArgs.cs
- XamlHttpHandlerFactory.cs
- ZipIOLocalFileHeader.cs
- PropertyChangeTracker.cs
- StatusBarPanelClickEvent.cs
- AddressUtility.cs
- BrowserDefinition.cs
- FlowDecision.cs
- VisemeEventArgs.cs
- FontStretch.cs
- ViewManager.cs
- VoiceObjectToken.cs
- ResourcePropertyMemberCodeDomSerializer.cs
- EntityDataSourceContextDisposingEventArgs.cs
- HttpWebRequest.cs
- ElementNotEnabledException.cs
- ValueUtilsSmi.cs
- DeferredReference.cs
- GZipStream.cs
- RunWorkerCompletedEventArgs.cs
- QilInvokeEarlyBound.cs
- DoubleAnimationUsingPath.cs
- SecurityUtils.cs
- SoapWriter.cs
- SplineKeyFrames.cs
- SimpleModelProvider.cs
- DBConnection.cs
- ElementMarkupObject.cs
- RetrieveVirtualItemEventArgs.cs
- Block.cs
- IndentedTextWriter.cs
- FolderBrowserDialog.cs
- UserControlAutomationPeer.cs
- ExceptionHandler.cs
- TextEditorThreadLocalStore.cs
- ReferenceSchema.cs
- TimeSpanOrInfiniteConverter.cs
- CommandLineParser.cs
- XmlAnyElementAttributes.cs
- QueryContinueDragEventArgs.cs
- StickyNoteContentControl.cs
- TraceListener.cs
- SyntaxCheck.cs
- HtmlFormAdapter.cs
- Collection.cs
- TextParentUndoUnit.cs
- UInt16.cs
- AuthenticationConfig.cs
- InputScope.cs
- CollectionDataContract.cs
- FrameworkContentElement.cs
- OleDbTransaction.cs
- ConfigXmlComment.cs
- NavigatorOutput.cs
- NTAccount.cs
- keycontainerpermission.cs
- SpeechUI.cs
- CollectionConverter.cs
- PolyBezierSegmentFigureLogic.cs
- DBDataPermission.cs
- RelationshipNavigation.cs
- HostedElements.cs
- EventPrivateKey.cs
- DBDataPermission.cs
- FilterFactory.cs
- DataGridColumnsPage.cs
- TableProvider.cs
- FileInfo.cs
- Win32.cs
- CodeAssignStatement.cs
- GeneralTransform3D.cs
- ListViewItem.cs
- FileVersion.cs
- ServerIdentity.cs
- DnsPermission.cs
- LicenseManager.cs
- FileResponseElement.cs
- X509ChainElement.cs
- FillErrorEventArgs.cs
- HMACSHA512.cs
- SelectionWordBreaker.cs
- ListViewGroupCollectionEditor.cs
- HitTestWithGeometryDrawingContextWalker.cs
- DataViewManager.cs
- _NegotiateClient.cs