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
- BooleanSwitch.cs
- NamespaceList.cs
- PathFigure.cs
- Compress.cs
- WebPartDisplayModeCollection.cs
- LoginUtil.cs
- SignatureHelper.cs
- OpCodes.cs
- DrawingVisualDrawingContext.cs
- RequestCache.cs
- SystemIPGlobalProperties.cs
- Quack.cs
- PersistChildrenAttribute.cs
- GeneralTransform3DTo2DTo3D.cs
- FlowLayoutPanel.cs
- AutomationPropertyInfo.cs
- OleDbWrapper.cs
- CreatingCookieEventArgs.cs
- counter.cs
- ImageMap.cs
- cryptoapiTransform.cs
- ThumbAutomationPeer.cs
- WeakReferenceList.cs
- SystemIPInterfaceStatistics.cs
- documentsequencetextcontainer.cs
- RegistrationServices.cs
- SqlProfileProvider.cs
- MetadataElement.cs
- PersistenceContextEnlistment.cs
- ComponentSerializationService.cs
- _SslSessionsCache.cs
- ViewValidator.cs
- DynamicRenderer.cs
- PagerStyle.cs
- HelloOperation11AsyncResult.cs
- BamlRecordWriter.cs
- RewritingSimplifier.cs
- XmlDataProvider.cs
- FileLevelControlBuilderAttribute.cs
- Knowncolors.cs
- SQLCharsStorage.cs
- DataGridViewColumnCollectionDialog.cs
- AttachmentCollection.cs
- ListBase.cs
- XmlDataLoader.cs
- EntityStoreSchemaGenerator.cs
- HelpProvider.cs
- TemplateManager.cs
- CodeBinaryOperatorExpression.cs
- JulianCalendar.cs
- Convert.cs
- ApplicationCommands.cs
- EntityDataReader.cs
- CommandLibraryHelper.cs
- DbConnectionStringCommon.cs
- TableCellsCollectionEditor.cs
- IncrementalHitTester.cs
- UnSafeCharBuffer.cs
- StatusBarDrawItemEvent.cs
- EUCJPEncoding.cs
- WindowsTooltip.cs
- ClientTarget.cs
- MaterialGroup.cs
- XmlSchemaSimpleTypeRestriction.cs
- StretchValidation.cs
- CapiSymmetricAlgorithm.cs
- WsdlBuildProvider.cs
- LinqTreeNodeEvaluator.cs
- DomNameTable.cs
- ItemDragEvent.cs
- DiagnosticSection.cs
- DataServiceProcessingPipelineEventArgs.cs
- SafeFileMapViewHandle.cs
- RectValueSerializer.cs
- DataGridViewElement.cs
- BitmapEffectDrawingContextWalker.cs
- GrammarBuilderPhrase.cs
- EventDescriptorCollection.cs
- ContainerParaClient.cs
- PropertyStore.cs
- MetaType.cs
- TextTreeFixupNode.cs
- CompilerParameters.cs
- TableLayoutStyle.cs
- SqlCacheDependencyDatabaseCollection.cs
- BinaryParser.cs
- KeyManager.cs
- TextBoxLine.cs
- RefreshInfo.cs
- ResXResourceReader.cs
- CacheEntry.cs
- TextReader.cs
- CodeStatementCollection.cs
- AppDomainGrammarProxy.cs
- FrameAutomationPeer.cs
- ClientConfigPaths.cs
- QilUnary.cs
- WebBrowserContainer.cs
- SQLString.cs
- TypeLoadException.cs