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
- InvokeGenerator.cs
- WebServiceMethodData.cs
- DataFieldCollectionEditor.cs
- ExtensionFile.cs
- ClientSponsor.cs
- SqlDelegatedTransaction.cs
- DefaultShape.cs
- MailFileEditor.cs
- panel.cs
- DocumentReference.cs
- RequestSecurityTokenSerializer.cs
- SpellCheck.cs
- RenameRuleObjectDialog.cs
- DomainUpDown.cs
- TextInfo.cs
- ClientUtils.cs
- HttpContext.cs
- BamlLocalizerErrorNotifyEventArgs.cs
- FederatedMessageSecurityOverHttpElement.cs
- BamlCollectionHolder.cs
- RenderData.cs
- XmlSchemaInfo.cs
- StateFinalizationActivity.cs
- Dispatcher.cs
- GPRECT.cs
- dataobject.cs
- DataGridPagerStyle.cs
- XmlElementAttributes.cs
- KnownBoxes.cs
- KeyedCollection.cs
- LayoutTable.cs
- TopClause.cs
- ScriptBehaviorDescriptor.cs
- DataGridCaption.cs
- ClickablePoint.cs
- BitmapScalingModeValidation.cs
- ComUdtElementCollection.cs
- LineMetrics.cs
- ProcessInfo.cs
- DeadCharTextComposition.cs
- KeyConverter.cs
- GridEntryCollection.cs
- CodeLabeledStatement.cs
- PointHitTestResult.cs
- AppDomainProtocolHandler.cs
- TextBoxDesigner.cs
- AnnotationResourceCollection.cs
- InkPresenterAutomationPeer.cs
- GridViewUpdateEventArgs.cs
- SHA1CryptoServiceProvider.cs
- controlskin.cs
- SimpleFieldTemplateFactory.cs
- Point4DValueSerializer.cs
- _TimerThread.cs
- DataControlFieldCollection.cs
- PtsHost.cs
- DesignerTextWriter.cs
- ReferenceEqualityComparer.cs
- EmptyReadOnlyDictionaryInternal.cs
- HttpCachePolicyElement.cs
- IndentedWriter.cs
- InternalReceiveMessage.cs
- CodeTypeReferenceCollection.cs
- DataServiceRequestException.cs
- SQLByte.cs
- LateBoundBitmapDecoder.cs
- Int64.cs
- MappingException.cs
- lengthconverter.cs
- GetIndexBinder.cs
- MultilineStringConverter.cs
- TableLayoutSettings.cs
- QueryCacheKey.cs
- DescendentsWalker.cs
- DataGridViewTextBoxColumn.cs
- TextRunCacheImp.cs
- IdentitySection.cs
- RadioButtonList.cs
- TextTreeObjectNode.cs
- oledbconnectionstring.cs
- DoubleAnimation.cs
- ImageBrush.cs
- DESCryptoServiceProvider.cs
- AggregateNode.cs
- ComponentChangingEvent.cs
- CollaborationHelperFunctions.cs
- DataControlFieldHeaderCell.cs
- WorkflowFileItem.cs
- ExpressionNode.cs
- LinqDataSourceDisposeEventArgs.cs
- GetWorkflowTree.cs
- BinaryWriter.cs
- messageonlyhwndwrapper.cs
- DefaultAssemblyResolver.cs
- DetailsViewDeletedEventArgs.cs
- ManagementOptions.cs
- JapaneseCalendar.cs
- ScrollBarRenderer.cs
- ShutDownListener.cs
- TargetParameterCountException.cs