Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / cdf / src / NetFx40 / System.Activities / System / Activities / Statements / TimerTable.cs / 1305376 / TimerTable.cs
//------------------------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- namespace System.Activities.Statements { using System; using System.Collections.Generic; using System.Linq; using System.Runtime; using System.Runtime.Serialization; // This class won't be thread safe, it relies on the callers to synchronize addTimer and removeTimer [DataContract] class TimerTable : IDisposable { [DataMember] SortedTimerList sortedTimerList; Dictionarytimers; IOThreadTimer activeTimer; bool isImmutable; Bookmark pendingRemoveBookmark; Bookmark pendingRetryBookmark; public TimerTable(DurableTimerExtension timerExtension) { this.timers = new Dictionary (); // Keep a sorted version of the list, so we don't have to loop through the whole list of timers everytime this.sortedTimerList = new SortedTimerList(); this.activeTimer = new IOThreadTimer(timerExtension.OnTimerFiredCallback, null, false, 0); } public int Count { get { return this.sortedTimerList.Count; } } public void AddTimer(TimeSpan timeout, Bookmark bookmark) { // Add timer is only called on the workflow thread, // It can't be racing with the persistence thread. // So the table MUST be mutable when this method is called Fx.Assert(!this.isImmutable, "Add timer is called when table is immutable"); DateTime dueTime = TimeoutHelper.Add(DateTime.UtcNow, timeout); TimerData timerData = new TimerData(bookmark, dueTime); this.timers.Add(bookmark, timerData); if (this.sortedTimerList.Count == 0) { this.sortedTimerList.Add(timerData); this.activeTimer.Set(timeout); } else { TimerData latestTimer = this.sortedTimerList.First(); this.sortedTimerList.Add(timerData); if (latestTimer.ExpirationTime > dueTime) { this.activeTimer.Set(timeout); } } } public void RemoveTimer(Bookmark bookmark) { // When IOThread Timer calls back, it will call remove timer // In another thread, we may be in the middle of persistence. // During persisting, we will mark the table as immutable // After we are done writing to the database, we will buffer the remove request // Meanwhile, since we are not scheduling any IOThreadTimers, // we can only have at most one pending Remove request // We don't want to remove if (!this.isImmutable) { TimerData expirationTimeData; if (this.timers.TryGetValue(bookmark, out expirationTimeData)) { // Check if we need to schedule the next IOThread Timer TimerData currentActiveTimer = this.sortedTimerList.First(); this.timers.Remove(bookmark); this.sortedTimerList.Remove(expirationTimeData); if (currentActiveTimer.Equals(expirationTimeData)) { this.activeTimer.Cancel(); if (this.sortedTimerList.Count > 0) { TimerData newActiveTimer = this.sortedTimerList.First(); this.activeTimer.Set(newActiveTimer.ExpirationTime - DateTime.UtcNow); } } } } else { this.pendingRemoveBookmark = bookmark; } } // Remove the timer from the table, and set expiration date to a new value. public void RetryTimer(Bookmark bookmark) { // This value controls how many seconds do we retry const int retryDuration = 10; // When IOThread Timer calls back, it might call RetryTimer timer if ResumeBookmark returned notReady // In another thread, we may be in the middle of persistence. // During persisting, we will mark the table as immutable // After we are done writing to the database, we will buffer the remove request // Meanwhile, since we are not scheduling any IOThreadTimers, // we can only have at most one pending Remove request // We don't want to remove if (!this.isImmutable) { TimerData expirationTimeData; if (this.timers.TryGetValue(bookmark, out expirationTimeData)) { // Check if we need to schedule the next IOThread Timer TimerData currentActiveTimer = this.sortedTimerList.First(); this.timers.Remove(bookmark); this.sortedTimerList.Remove(expirationTimeData); // Update it to the retry time and put it back to the timer list DateTime newExpirationTime = TimeoutHelper.Add(DateTime.UtcNow, TimeSpan.FromSeconds(retryDuration)); TimerData retryTimer = new TimerData(bookmark, newExpirationTime); this.timers.Add(bookmark, retryTimer); this.sortedTimerList.Add(retryTimer); TimerData newActiveTimer = this.sortedTimerList.First(); this.activeTimer.Set(newActiveTimer.ExpirationTime - DateTime.UtcNow); } } else { this.pendingRetryBookmark = bookmark; } } public DateTime GetNextDueTime() { DateTime nextDueTime = DateTime.MaxValue; if (this.sortedTimerList.Count > 0) { nextDueTime = this.sortedTimerList.First().ExpirationTime; } return nextDueTime; } public Bookmark GetNextExpiredBookmark() { Bookmark bookmark = null; if (this.sortedTimerList.Count > 0) { bookmark = this.sortedTimerList.First().Bookmark; } return bookmark; } public void OnLoad(DurableTimerExtension timerExtension) { this.timers = new Dictionary (); this.activeTimer = new IOThreadTimer(timerExtension.OnTimerFiredCallback, null, false, 0); foreach (TimerData timeData in this.sortedTimerList.Timers) { this.timers.Add(timeData.Bookmark, timeData); } if (this.sortedTimerList.Count > 0) { TimerData currentActiveTimer = this.sortedTimerList.First(); if (currentActiveTimer.ExpirationTime <= DateTime.UtcNow) { // If the timer expired, we want to fire it immediately to win the ---- against UnloadOnIdle policy timerExtension.OnTimerFiredCallback(currentActiveTimer.Bookmark); } else { this.activeTimer.Set(currentActiveTimer.ExpirationTime - DateTime.UtcNow); } } } public void MarkAsImmutable() { this.isImmutable = true; } public void MarkAsMutable() { if (this.isImmutable) { this.isImmutable = false; if (this.pendingRemoveBookmark != null) { this.RemoveTimer(this.pendingRemoveBookmark); this.pendingRemoveBookmark = null; } if (this.pendingRetryBookmark != null) { this.RetryTimer(this.pendingRetryBookmark); this.pendingRetryBookmark = null; } } } public void Dispose() { // Cancel the active timer so we stop retrying this.activeTimer.Cancel(); // And we clear the table and other member variables that might cause the retry logic this.timers.Clear(); this.sortedTimerList.Clear(); this.pendingRemoveBookmark = null; this.pendingRetryBookmark = null; } [DataContract] class SortedTimerList { [DataMember] List list; TimerComparer timerComparer; public SortedTimerList() { this.list = new List (); } public List Timers { get { return this.list; } } // Assume that the caller would synchronize TimerComparer TimerComparer { get { if (this.timerComparer == null) { this.timerComparer = new TimerComparer(); } return this.timerComparer; } } public int Count { get { return this.list.Count; } } public void Add(TimerData timerData) { int index = this.list.BinarySearch(timerData, this.TimerComparer); if (index < 0) { this.list.Insert(~index, timerData); } } public void Remove(TimerData timerData) { int index = this.list.BinarySearch(timerData, this.TimerComparer); if (index >= 0) { this.list.RemoveAt(index); } } public TimerData First() { return this.list.First(); } public void Clear() { this.list.Clear(); } } class TimerComparer : IComparer { public int Compare(TimerData x, TimerData y) { if (object.ReferenceEquals(x, y)) { return 0; } else { if (x == null) { return -1; } else { if (y == null) { return 1; } else { if (x.ExpirationTime == y.ExpirationTime) { if (x.Bookmark.IsNamed) { if (y.Bookmark.IsNamed) { return string.Compare(x.Bookmark.Name, y.Bookmark.Name, StringComparison.OrdinalIgnoreCase); } else { return 1; } } else { if (y.Bookmark.IsNamed) { return -1; } else { return x.Bookmark.Id.CompareTo(y.Bookmark.Id); } } } else { return x.ExpirationTime.CompareTo(y.ExpirationTime); } } } } } } [DataContract] class TimerData : IEquatable { public TimerData(Bookmark bookmark, DateTime expirationTime) { this.Bookmark = bookmark; this.ExpirationTime = expirationTime; } [DataMember] public Bookmark Bookmark { get; private set; } [DataMember] public DateTime ExpirationTime { get; private set; } public bool Equals(TimerData other) { if (this.ExpirationTime == other.ExpirationTime) { return this.Bookmark.Equals(other.Bookmark); } else { return this.ExpirationTime.Equals(other.ExpirationTime); } } } } } // 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
- HtmlSelect.cs
- SuppressMessageAttribute.cs
- CodeThrowExceptionStatement.cs
- URL.cs
- PageRequestManager.cs
- SettingsAttributeDictionary.cs
- HttpContext.cs
- DataService.cs
- Lock.cs
- SamlSubjectStatement.cs
- DecoderBestFitFallback.cs
- BindingListCollectionView.cs
- DataAccessException.cs
- ObjectManager.cs
- CounterCreationDataConverter.cs
- DataList.cs
- DataGridItemCollection.cs
- TimeoutTimer.cs
- FixedTextView.cs
- Int64Converter.cs
- ElementMarkupObject.cs
- DependencyPropertyChangedEventArgs.cs
- XmlSchemaSearchPattern.cs
- ControlUtil.cs
- Config.cs
- DbDataRecord.cs
- XmlReturnWriter.cs
- TabletDeviceInfo.cs
- PerfService.cs
- QilValidationVisitor.cs
- DBNull.cs
- GraphicsPath.cs
- HandoffBehavior.cs
- validation.cs
- EntityTypeEmitter.cs
- ZipPackagePart.cs
- SettingsPropertyWrongTypeException.cs
- CatalogZoneDesigner.cs
- MultipartContentParser.cs
- InvokePatternIdentifiers.cs
- Vector.cs
- XmlIlGenerator.cs
- CryptoConfig.cs
- DesignerActionList.cs
- ExecutorLocksHeldException.cs
- SQLDecimalStorage.cs
- FloaterParagraph.cs
- KernelTypeValidation.cs
- QuotedStringFormatReader.cs
- WizardStepCollectionEditor.cs
- ImagingCache.cs
- ClrProviderManifest.cs
- PrtTicket_Public.cs
- Canvas.cs
- CodeGenerationManager.cs
- UserControl.cs
- ComplexObject.cs
- EventListener.cs
- RangeValuePattern.cs
- UnmanagedHandle.cs
- DocumentDesigner.cs
- DataSysAttribute.cs
- Boolean.cs
- SecUtil.cs
- XhtmlBasicLiteralTextAdapter.cs
- WebPartConnectionsConnectVerb.cs
- BuilderPropertyEntry.cs
- ContextBase.cs
- XmlIncludeAttribute.cs
- SHA256Cng.cs
- ExtentKey.cs
- FixedTextContainer.cs
- ResponseBodyWriter.cs
- ArgumentException.cs
- WebFormsRootDesigner.cs
- SafeEventLogReadHandle.cs
- EpmSourceTree.cs
- SqlRemoveConstantOrderBy.cs
- FormatConvertedBitmap.cs
- GenericAuthenticationEventArgs.cs
- SamlAction.cs
- AccessDataSource.cs
- AxWrapperGen.cs
- ControlDesigner.cs
- PowerModeChangedEventArgs.cs
- TreeNodeEventArgs.cs
- TdsParserSessionPool.cs
- ResourceDescriptionAttribute.cs
- ScriptManager.cs
- RSAPKCS1KeyExchangeFormatter.cs
- ComponentCommands.cs
- Matrix3D.cs
- XmlSchemaComplexType.cs
- CountAggregationOperator.cs
- UpdateException.cs
- EventLogPropertySelector.cs
- InlineCollection.cs
- HtmlEmptyTagControlBuilder.cs
- DataGridTextBox.cs
- ArraySegment.cs