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
- SiteMapNodeItem.cs
- complextypematerializer.cs
- SqlUtils.cs
- ChangeTracker.cs
- SelectionItemProviderWrapper.cs
- _NegoStream.cs
- HMACSHA256.cs
- DebugView.cs
- SamlAuthorizationDecisionClaimResource.cs
- SafeRightsManagementHandle.cs
- PageRequestManager.cs
- DataGridViewBand.cs
- TableLayoutPanel.cs
- DrawingGroupDrawingContext.cs
- ExtensionCollection.cs
- ImageKeyConverter.cs
- compensatingcollection.cs
- MailDefinitionBodyFileNameEditor.cs
- BufferedStream.cs
- DataGridViewCellPaintingEventArgs.cs
- WebPartMenu.cs
- DocumentViewerBase.cs
- SetUserLanguageRequest.cs
- DataGridViewCellStyle.cs
- Root.cs
- FacetChecker.cs
- GenericXmlSecurityToken.cs
- TTSEngineTypes.cs
- CorrelationQueryBehavior.cs
- MenuTracker.cs
- TraceInternal.cs
- MediaContext.cs
- SafeProcessHandle.cs
- DodSequenceMerge.cs
- ObjectHelper.cs
- DeviceContext.cs
- Utils.cs
- RedirectionProxy.cs
- HostingEnvironmentWrapper.cs
- BitmapEffectDrawing.cs
- Atom10FeedFormatter.cs
- MD5.cs
- InputScopeNameConverter.cs
- CheckBoxRenderer.cs
- TreeNodeStyleCollection.cs
- BaseValidator.cs
- MediaTimeline.cs
- LambdaCompiler.Binary.cs
- SafeArrayRankMismatchException.cs
- SchemaObjectWriter.cs
- EtwTrace.cs
- QualificationDataItem.cs
- CachedCompositeFamily.cs
- WindowsPen.cs
- ScrollChrome.cs
- WindowsListViewItemCheckBox.cs
- WriteableOnDemandPackagePart.cs
- PointUtil.cs
- TimeSpanMinutesOrInfiniteConverter.cs
- ComponentResourceKeyConverter.cs
- JavaScriptSerializer.cs
- SchemaAttDef.cs
- ContextStaticAttribute.cs
- OperationGenerator.cs
- CalendarItem.cs
- TypeFieldSchema.cs
- XmlArrayAttribute.cs
- DbConnectionHelper.cs
- String.cs
- ManagementInstaller.cs
- XpsFont.cs
- TransactionFlowAttribute.cs
- WindowsEditBoxRange.cs
- ObjRef.cs
- CheckedListBox.cs
- AbstractDataSvcMapFileLoader.cs
- IssuedTokenClientBehaviorsElement.cs
- WorkflowPersistenceContext.cs
- NativeMethods.cs
- PropertyFilterAttribute.cs
- PathGradientBrush.cs
- MetafileEditor.cs
- MethodToken.cs
- Scene3D.cs
- TableCell.cs
- EditorPartCollection.cs
- StorageBasedPackageProperties.cs
- ClientTargetSection.cs
- InvalidFilterCriteriaException.cs
- ListBindingConverter.cs
- OperationExecutionFault.cs
- FileNameEditor.cs
- Keywords.cs
- XmlNamespaceManager.cs
- WeakEventTable.cs
- MarshalByRefObject.cs
- LabelEditEvent.cs
- StorageComplexPropertyMapping.cs
- QilUnary.cs
- HelloOperation11AsyncResult.cs