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;
Dictionary timers;
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
- GroupQuery.cs
- DatagridviewDisplayedBandsData.cs
- Rfc2898DeriveBytes.cs
- TraceFilter.cs
- BaseValidatorDesigner.cs
- ProviderConnectionPoint.cs
- Rules.cs
- SafeRegistryHandle.cs
- WmlControlAdapter.cs
- ChtmlTextWriter.cs
- XmlAnyAttributeAttribute.cs
- NestPullup.cs
- DynamicMetaObjectBinder.cs
- SqlDataSourceFilteringEventArgs.cs
- XamlDesignerSerializationManager.cs
- Span.cs
- PeerNameResolver.cs
- ReferenceConverter.cs
- VBCodeProvider.cs
- TreeNodeCollection.cs
- Function.cs
- XmlSchemaSequence.cs
- AxisAngleRotation3D.cs
- ValidatorAttribute.cs
- UriExt.cs
- PartialCachingControl.cs
- DataGridViewRowsRemovedEventArgs.cs
- SspiSafeHandles.cs
- StringAnimationUsingKeyFrames.cs
- IPAddress.cs
- ChannelFactoryRefCache.cs
- WinFormsUtils.cs
- ParserExtension.cs
- GuidelineCollection.cs
- ValuePattern.cs
- ByteConverter.cs
- DataGridViewRowsRemovedEventArgs.cs
- SystemIPv6InterfaceProperties.cs
- ConfigurationPermission.cs
- CommandField.cs
- HandledMouseEvent.cs
- XsdSchemaFileEditor.cs
- StaticResourceExtension.cs
- ToolBarPanel.cs
- LifetimeServices.cs
- RoleManagerEventArgs.cs
- MethodAccessException.cs
- RenderingEventArgs.cs
- Itemizer.cs
- NativeMethods.cs
- TextDecorationUnitValidation.cs
- OverrideMode.cs
- ImmutableCollection.cs
- StreamGeometry.cs
- BehaviorEditorPart.cs
- HttpCapabilitiesBase.cs
- FindCriteria.cs
- PackageRelationshipSelector.cs
- MetabaseServerConfig.cs
- HttpListenerResponse.cs
- AvtEvent.cs
- ColorKeyFrameCollection.cs
- LogExtentCollection.cs
- SoapTypeAttribute.cs
- SecureStringHasher.cs
- SelectionEditingBehavior.cs
- Walker.cs
- MouseWheelEventArgs.cs
- InstanceData.cs
- SystemIPv6InterfaceProperties.cs
- XamlTypeMapper.cs
- SqlReferenceCollection.cs
- UnsafeNativeMethods.cs
- SelectorItemAutomationPeer.cs
- CodeGenerator.cs
- DataKeyCollection.cs
- PropertyGridView.cs
- AppModelKnownContentFactory.cs
- RadioButtonList.cs
- AsymmetricKeyExchangeDeformatter.cs
- XmlUtf8RawTextWriter.cs
- SubclassTypeValidatorAttribute.cs
- CompositeScriptReference.cs
- CompiledIdentityConstraint.cs
- CounterCreationDataCollection.cs
- ToolStripDesignerAvailabilityAttribute.cs
- SingleSelectRootGridEntry.cs
- BitmapEffectDrawingContextState.cs
- ErrorEventArgs.cs
- altserialization.cs
- ScrollContentPresenter.cs
- StorageMappingFragment.cs
- DoubleAnimationClockResource.cs
- PropertyChangeTracker.cs
- Util.cs
- WebConfigurationManager.cs
- OleAutBinder.cs
- initElementDictionary.cs
- CookielessHelper.cs
- SHA1Managed.cs