Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / cdf / src / WCF / Log / System / IO / Log / FileRecordSequenceHelper.cs / 1305376 / FileRecordSequenceHelper.cs
//------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. //----------------------------------------------------------- namespace System.IO.Log { using System; using System.Runtime; using System.Threading; using System.Collections.Generic; // This class contains all the workarounds for simple file log. 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 (Fx.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 (Fx.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.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- SqlMetaData.cs
- ValidatedControlConverter.cs
- Int64Storage.cs
- OdbcPermission.cs
- WorkflowMarkupElementEventArgs.cs
- ObjectConverter.cs
- ToolboxComponentsCreatedEventArgs.cs
- ByteKeyFrameCollection.cs
- webbrowsersite.cs
- DataKey.cs
- TreeNodeBinding.cs
- TemplateManager.cs
- PrimitiveCodeDomSerializer.cs
- DataObjectFieldAttribute.cs
- CodeDOMProvider.cs
- XmlILModule.cs
- Int32.cs
- TdsEnums.cs
- EmptyEnumerator.cs
- DataMemberConverter.cs
- BuildProvider.cs
- SessionStateContainer.cs
- Cursor.cs
- ByteStorage.cs
- SafePEFileHandle.cs
- ZipFileInfoCollection.cs
- QueryCacheEntry.cs
- ReliabilityContractAttribute.cs
- PersonalizationProviderHelper.cs
- cookiecollection.cs
- documentsequencetextcontainer.cs
- QuaternionRotation3D.cs
- MD5.cs
- WindowsTokenRoleProvider.cs
- DebugHandleTracker.cs
- DebugViewWriter.cs
- XamlPathDataSerializer.cs
- ContextDataSource.cs
- MenuItemCollection.cs
- DemultiplexingClientMessageFormatter.cs
- TextEffect.cs
- XamlToRtfParser.cs
- CopyOfAction.cs
- SqlUDTStorage.cs
- CqlLexer.cs
- SchemaMerger.cs
- assertwrapper.cs
- IncrementalHitTester.cs
- DateTimeFormatInfo.cs
- ZipIOEndOfCentralDirectoryBlock.cs
- ExpressionEvaluator.cs
- RoleManagerModule.cs
- DataGridViewCellMouseEventArgs.cs
- ExpressionDumper.cs
- PropertyBuilder.cs
- SerialErrors.cs
- MsmqException.cs
- AudioFileOut.cs
- ViewStateException.cs
- MenuCommand.cs
- _NTAuthentication.cs
- DBConnectionString.cs
- ConfigViewGenerator.cs
- RichTextBox.cs
- BindingWorker.cs
- NativeWrapper.cs
- TypeCollectionPropertyEditor.cs
- CodeDefaultValueExpression.cs
- SerialReceived.cs
- CompleteWizardStep.cs
- WorkflowApplicationIdleEventArgs.cs
- AttributeQuery.cs
- SiteMapNodeItemEventArgs.cs
- XmlCharCheckingReader.cs
- Relationship.cs
- FtpRequestCacheValidator.cs
- ToolStripProfessionalLowResolutionRenderer.cs
- Dispatcher.cs
- SafePipeHandle.cs
- DataTransferEventArgs.cs
- ConstraintManager.cs
- DetailsViewPagerRow.cs
- BindingListCollectionView.cs
- SerializerWriterEventHandlers.cs
- DesignerHierarchicalDataSourceView.cs
- Model3D.cs
- OperatingSystem.cs
- DataPagerFieldCollection.cs
- GreenMethods.cs
- SerializationException.cs
- VolatileResourceManager.cs
- StringAnimationBase.cs
- StylusTouchDevice.cs
- RegistryPermission.cs
- ChangeTracker.cs
- VirtualDirectoryMapping.cs
- NotFiniteNumberException.cs
- TreeViewItemAutomationPeer.cs
- TextCompositionManager.cs
- ErrorFormatter.cs