1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
|
//-----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
namespace System.Runtime
{
using System;
using System.Threading;
sealed class BackoffTimeoutHelper
{
readonly static int maxSkewMilliseconds = (int)(IOThreadTimer.SystemTimeResolutionTicks / TimeSpan.TicksPerMillisecond);
readonly static long maxDriftTicks = IOThreadTimer.SystemTimeResolutionTicks * 2;
readonly static TimeSpan defaultInitialWaitTime = TimeSpan.FromMilliseconds(1);
readonly static TimeSpan defaultMaxWaitTime = TimeSpan.FromMinutes(1);
DateTime deadline;
TimeSpan maxWaitTime;
TimeSpan waitTime;
IOThreadTimer backoffTimer;
Action<object> backoffCallback;
object backoffState;
Random random;
TimeSpan originalTimeout;
internal BackoffTimeoutHelper(TimeSpan timeout)
: this(timeout, BackoffTimeoutHelper.defaultMaxWaitTime)
{
}
internal BackoffTimeoutHelper(TimeSpan timeout, TimeSpan maxWaitTime)
: this(timeout, maxWaitTime, BackoffTimeoutHelper.defaultInitialWaitTime)
{
}
internal BackoffTimeoutHelper(TimeSpan timeout, TimeSpan maxWaitTime, TimeSpan initialWaitTime)
{
this.random = new Random(GetHashCode());
this.maxWaitTime = maxWaitTime;
this.originalTimeout = timeout;
Reset(timeout, initialWaitTime);
}
public TimeSpan OriginalTimeout
{
get
{
return this.originalTimeout;
}
}
void Reset(TimeSpan timeout, TimeSpan initialWaitTime)
{
if (timeout == TimeSpan.MaxValue)
{
this.deadline = DateTime.MaxValue;
}
else
{
this.deadline = DateTime.UtcNow + timeout;
}
this.waitTime = initialWaitTime;
}
public bool IsExpired()
{
if (this.deadline == DateTime.MaxValue)
{
return false;
}
else
{
return (DateTime.UtcNow >= this.deadline);
}
}
public void WaitAndBackoff(Action<object> callback, object state)
{
if (this.backoffCallback != callback || this.backoffState != state)
{
if (this.backoffTimer != null)
{
this.backoffTimer.Cancel();
}
this.backoffCallback = callback;
this.backoffState = state;
this.backoffTimer = new IOThreadTimer(callback, state, false, BackoffTimeoutHelper.maxSkewMilliseconds);
}
TimeSpan backoffTime = WaitTimeWithDrift();
Backoff();
this.backoffTimer.Set(backoffTime);
}
public void WaitAndBackoff()
{
Thread.Sleep(WaitTimeWithDrift());
Backoff();
}
TimeSpan WaitTimeWithDrift()
{
return Ticks.ToTimeSpan(Math.Max(
Ticks.FromTimeSpan(BackoffTimeoutHelper.defaultInitialWaitTime),
Ticks.Add(Ticks.FromTimeSpan(this.waitTime),
(long)(uint)this.random.Next() % (2 * BackoffTimeoutHelper.maxDriftTicks + 1) - BackoffTimeoutHelper.maxDriftTicks)));
}
void Backoff()
{
if (waitTime.Ticks >= (maxWaitTime.Ticks / 2))
{
waitTime = maxWaitTime;
}
else
{
waitTime = TimeSpan.FromTicks(waitTime.Ticks * 2);
}
if (this.deadline != DateTime.MaxValue)
{
TimeSpan remainingTime = this.deadline - DateTime.UtcNow;
if (this.waitTime > remainingTime)
{
this.waitTime = remainingTime;
if (this.waitTime < TimeSpan.Zero)
{
this.waitTime = TimeSpan.Zero;
}
}
}
}
}
}
|