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
- OleCmdHelper.cs
- Terminate.cs
- MD5CryptoServiceProvider.cs
- PopupEventArgs.cs
- SQLRoleProvider.cs
- webclient.cs
- XmlFormatExtensionPointAttribute.cs
- GeometryModel3D.cs
- XmlHelper.cs
- ComponentChangedEvent.cs
- SafeRightsManagementQueryHandle.cs
- baseshape.cs
- SettingsPropertyNotFoundException.cs
- IndependentAnimationStorage.cs
- ObjectListField.cs
- ErrorView.xaml.cs
- SafeNativeMethods.cs
- DataContract.cs
- HwndKeyboardInputProvider.cs
- SqlMethodAttribute.cs
- TypeInfo.cs
- CroppedBitmap.cs
- SplitterEvent.cs
- LinqDataSourceHelper.cs
- ReceiveActivity.cs
- XmlTextAttribute.cs
- UdpUtility.cs
- CodeRegionDirective.cs
- EntityDataSourceConfigureObjectContext.cs
- TypeConverterHelper.cs
- ServicesUtilities.cs
- ByteStreamGeometryContext.cs
- HitTestResult.cs
- WorkflowInstance.cs
- SchemaImporterExtensionElement.cs
- XmlCharCheckingWriter.cs
- TypefaceCollection.cs
- EntityExpressionVisitor.cs
- TextEndOfSegment.cs
- MultiDataTrigger.cs
- DllHostedComPlusServiceHost.cs
- UrlPropertyAttribute.cs
- PointLight.cs
- DependencyProperty.cs
- MarginCollapsingState.cs
- GB18030Encoding.cs
- QuaternionAnimation.cs
- ItemsControl.cs
- ReliableChannelFactory.cs
- Knowncolors.cs
- FileDialogPermission.cs
- ExtensionDataReader.cs
- FormsAuthenticationModule.cs
- SelectorAutomationPeer.cs
- KeyEvent.cs
- DataAccessException.cs
- SqlRewriteScalarSubqueries.cs
- StateMachineSubscriptionManager.cs
- DocumentSequenceHighlightLayer.cs
- XmlUtilWriter.cs
- UdpChannelFactory.cs
- SQLRoleProvider.cs
- MailAddress.cs
- UIElement3D.cs
- SchemaImporterExtensionElement.cs
- SelectionUIHandler.cs
- ControlCachePolicy.cs
- RemotingService.cs
- MimeFormatter.cs
- XmlSchemaObjectTable.cs
- LinqDataSourceContextEventArgs.cs
- DataSourceView.cs
- DelegateSerializationHolder.cs
- BinHexEncoder.cs
- Context.cs
- SHA512Cng.cs
- DataGridTextColumn.cs
- _NestedMultipleAsyncResult.cs
- TraceContextEventArgs.cs
- SerializationSectionGroup.cs
- ContainerFilterService.cs
- MDIClient.cs
- IsolatedStorageFile.cs
- KeyEventArgs.cs
- DataControlImageButton.cs
- SymbolTable.cs
- NetMsmqBinding.cs
- AutomationEventArgs.cs
- DetailsViewRow.cs
- ScrollableControl.cs
- BookmarkInfo.cs
- XmlTextReaderImplHelpers.cs
- Effect.cs
- RelationshipWrapper.cs
- EntityTypeEmitter.cs
- IDReferencePropertyAttribute.cs
- ResourceExpressionBuilder.cs
- WebPartDisplayModeCancelEventArgs.cs
- DrawingImage.cs
- WindowsImpersonationContext.cs