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
- AspCompat.cs
- SpotLight.cs
- PageTheme.cs
- WebWorkflowRole.cs
- DetailsViewRow.cs
- UserControl.cs
- WindowsFormsHelpers.cs
- FreeFormDesigner.cs
- HtmlInputPassword.cs
- MulticastNotSupportedException.cs
- ConfigXmlWhitespace.cs
- RotationValidation.cs
- ScriptingJsonSerializationSection.cs
- TemplateBuilder.cs
- PropertyRef.cs
- PositiveTimeSpanValidator.cs
- Properties.cs
- ProgressBarBrushConverter.cs
- RangeExpression.cs
- BitmapSizeOptions.cs
- XpsSerializationException.cs
- HttpFileCollection.cs
- ClientTarget.cs
- MimeMultiPart.cs
- ScopelessEnumAttribute.cs
- safemediahandle.cs
- DuplicateWaitObjectException.cs
- SrgsElementFactoryCompiler.cs
- DirtyTextRange.cs
- UIElementPropertyUndoUnit.cs
- NavigationHelper.cs
- MenuRenderer.cs
- LoginCancelEventArgs.cs
- XmlCodeExporter.cs
- ValidationError.cs
- RoleGroup.cs
- CodeTypeDeclarationCollection.cs
- APCustomTypeDescriptor.cs
- TypeGeneratedEventArgs.cs
- RewritingPass.cs
- CodeNamespaceImport.cs
- SortedDictionary.cs
- TextRunTypographyProperties.cs
- DoubleCollectionConverter.cs
- ToolStripDropDownClosingEventArgs.cs
- Point3DKeyFrameCollection.cs
- ServiceRoute.cs
- Util.cs
- BaseAppDomainProtocolHandler.cs
- DeferredBinaryDeserializerExtension.cs
- ReverseInheritProperty.cs
- DeviceContexts.cs
- Label.cs
- SourceSwitch.cs
- Stroke2.cs
- ModuleBuilder.cs
- StyleModeStack.cs
- DataControlExtensions.cs
- DataStreams.cs
- MultiDataTrigger.cs
- WorkflowValidationFailedException.cs
- SessionState.cs
- InsufficientMemoryException.cs
- DbConnectionPoolGroup.cs
- TdsParserStaticMethods.cs
- SwitchElementsCollection.cs
- ParserContext.cs
- RemoteCryptoDecryptRequest.cs
- AlternateView.cs
- SafePipeHandle.cs
- MailDefinition.cs
- NamedPermissionSet.cs
- FormsAuthenticationUser.cs
- WorkflowPageSetupDialog.cs
- SocketException.cs
- SocketInformation.cs
- HyperLinkField.cs
- EventBookmark.cs
- ErrorFormatter.cs
- IChannel.cs
- DockPattern.cs
- ArrayList.cs
- DbProviderFactoriesConfigurationHandler.cs
- ClosableStream.cs
- ChannelTracker.cs
- LocationUpdates.cs
- OutputCacheSection.cs
- TraceUtility.cs
- SpotLight.cs
- ComponentRenameEvent.cs
- NativeMethods.cs
- WindowsComboBox.cs
- XmlSchemaAppInfo.cs
- FamilyTypefaceCollection.cs
- VirtualDirectoryMappingCollection.cs
- TemplateField.cs
- complextypematerializer.cs
- PrintingPermissionAttribute.cs
- FunctionDetailsReader.cs
- Camera.cs