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
- InputMethodStateTypeInfo.cs
- TcpSocketManager.cs
- SystemIPInterfaceStatistics.cs
- SqlServer2KCompatibilityAnnotation.cs
- NumberFormatter.cs
- SimpleBitVector32.cs
- WindowsEditBoxRange.cs
- HttpProcessUtility.cs
- KeyValueSerializer.cs
- RTLAwareMessageBox.cs
- SBCSCodePageEncoding.cs
- SemaphoreSecurity.cs
- ReturnType.cs
- WmlSelectionListAdapter.cs
- SpeakProgressEventArgs.cs
- MasterPage.cs
- InkPresenterAutomationPeer.cs
- StreamUpdate.cs
- ProxyFragment.cs
- BaseDataList.cs
- TrackingParameters.cs
- SizeFConverter.cs
- AlignmentYValidation.cs
- XmlHelper.cs
- ListItemCollection.cs
- SchemaTypeEmitter.cs
- RawStylusInputCustomDataList.cs
- Input.cs
- HostingPreferredMapPath.cs
- MatrixUtil.cs
- Lease.cs
- StartUpEventArgs.cs
- OutputCacheModule.cs
- StringUtil.cs
- SafeProcessHandle.cs
- MetadataArtifactLoader.cs
- WebBrowserUriTypeConverter.cs
- dataobject.cs
- Win32Exception.cs
- BaseInfoTable.cs
- HttpProxyCredentialType.cs
- TreeViewImageIndexConverter.cs
- CachedFontFace.cs
- DbConnectionPool.cs
- MediaElementAutomationPeer.cs
- DockPattern.cs
- FixedFindEngine.cs
- RestHandlerFactory.cs
- XmlSchemaGroup.cs
- ExtenderHelpers.cs
- WorkflowQueue.cs
- Line.cs
- InvalidComObjectException.cs
- TextContainer.cs
- BehaviorDragDropEventArgs.cs
- BaseParser.cs
- CmsInterop.cs
- SmiContext.cs
- UxThemeWrapper.cs
- EntityDesignerBuildProvider.cs
- DoubleCollectionConverter.cs
- WebPartConnectionsCancelEventArgs.cs
- BuildResultCache.cs
- AccessDataSourceDesigner.cs
- PlainXmlSerializer.cs
- AppDomainAttributes.cs
- TraceInternal.cs
- AsymmetricAlgorithm.cs
- PrimitiveXmlSerializers.cs
- ShaderEffect.cs
- FocusChangedEventArgs.cs
- DataSetMappper.cs
- DTCTransactionManager.cs
- SqlDelegatedTransaction.cs
- CryptoApi.cs
- SignedPkcs7.cs
- ListBase.cs
- ListMarkerLine.cs
- KeyNotFoundException.cs
- Timeline.cs
- SmtpNetworkElement.cs
- ActivityWithResultValueSerializer.cs
- DesignTimeVisibleAttribute.cs
- DbProviderFactory.cs
- FullTrustAssemblyCollection.cs
- SymDocumentType.cs
- OutputCacheProfile.cs
- VirtualizingPanel.cs
- ActiveXSite.cs
- IsolatedStorageFilePermission.cs
- DbConnectionFactory.cs
- ProgressPage.cs
- ExpressionEditor.cs
- DateRangeEvent.cs
- ContextMenu.cs
- EventListenerClientSide.cs
- XdrBuilder.cs
- Maps.cs
- TransformerTypeCollection.cs
- SrgsElementList.cs