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
- Point3DConverter.cs
- TextOptionsInternal.cs
- CodeDefaultValueExpression.cs
- UnicastIPAddressInformationCollection.cs
- Regex.cs
- CredentialCache.cs
- ReflectionUtil.cs
- PointLight.cs
- ResourceDescriptionAttribute.cs
- BoolLiteral.cs
- ComboBoxAutomationPeer.cs
- CompiledXpathExpr.cs
- LiteralTextParser.cs
- EncryptedKey.cs
- XsltContext.cs
- XmlSchemaElement.cs
- ComponentManagerBroker.cs
- DefaultProxySection.cs
- SymmetricKeyWrap.cs
- Rectangle.cs
- DocumentsTrace.cs
- StatusBar.cs
- SQLRoleProvider.cs
- Part.cs
- DataGridViewCellStyleChangedEventArgs.cs
- DataRelation.cs
- OdbcDataAdapter.cs
- ValidationSummary.cs
- Compilation.cs
- ImageListUtils.cs
- CacheEntry.cs
- ClassHandlersStore.cs
- IisTraceWebEventProvider.cs
- IncrementalReadDecoders.cs
- UnsafeNativeMethods.cs
- XmlSchemaSimpleContent.cs
- UpdateExpressionVisitor.cs
- PropertyGridEditorPart.cs
- SignedXml.cs
- WindowsAuthenticationModule.cs
- WindowsIdentity.cs
- BitmapCache.cs
- DataStreamFromComStream.cs
- NavigationService.cs
- EntityContainer.cs
- CqlErrorHelper.cs
- DSASignatureFormatter.cs
- CallSiteOps.cs
- WorkflowDefinitionContext.cs
- TextServicesLoader.cs
- SchemaMapping.cs
- Subtree.cs
- Switch.cs
- Normalization.cs
- WebBrowserSiteBase.cs
- CompilerGeneratedAttribute.cs
- Oid.cs
- PrimaryKeyTypeConverter.cs
- TextBox.cs
- ManagementBaseObject.cs
- QueryLifecycle.cs
- CollaborationHelperFunctions.cs
- RelationshipDetailsRow.cs
- XamlWriter.cs
- XmlWriterSettings.cs
- SQLMoney.cs
- DoubleLinkListEnumerator.cs
- HebrewNumber.cs
- XPathAncestorIterator.cs
- SQLString.cs
- HttpListenerResponse.cs
- SmtpLoginAuthenticationModule.cs
- RemoteWebConfigurationHostStream.cs
- basecomparevalidator.cs
- ToolStripDropDownClosingEventArgs.cs
- ToolbarAUtomationPeer.cs
- ReaderContextStackData.cs
- SafeTimerHandle.cs
- DynamicRendererThreadManager.cs
- StrokeSerializer.cs
- MarkupProperty.cs
- RewritingPass.cs
- ComplexLine.cs
- ComEventsInfo.cs
- HierarchicalDataTemplate.cs
- PagesChangedEventArgs.cs
- ThrowHelper.cs
- NamespaceMapping.cs
- PrintPreviewControl.cs
- XmlSchemaException.cs
- FaultConverter.cs
- XmlTypeAttribute.cs
- MonikerProxyAttribute.cs
- ResourceManager.cs
- PathSegment.cs
- Geometry.cs
- TypeListConverter.cs
- AttachedPropertyBrowsableForChildrenAttribute.cs
- StringUtil.cs
- KeyedCollection.cs