@@ -11,11 +11,14 @@ internal sealed class TimeoutControl : ITimeoutControl, IConnectionTimeoutFeatur
11
11
{
12
12
private readonly ITimeoutHandler _timeoutHandler ;
13
13
14
+ private readonly long _heartbeatIntervalTicks ;
15
+ private readonly long _tickFrequency ;
14
16
private long _lastTimestamp ;
15
17
private long _timeoutTimestamp = long . MaxValue ;
16
18
17
19
private readonly object _readTimingLock = new object ( ) ;
18
20
private MinDataRate ? _minReadRate ;
21
+ private long _minReadRateGracePeriodTicks ;
19
22
private bool _readTimingEnabled ;
20
23
private bool _readTimingPauseRequested ;
21
24
private long _readTimingElapsedTicks ;
@@ -29,9 +32,11 @@ internal sealed class TimeoutControl : ITimeoutControl, IConnectionTimeoutFeatur
29
32
private int _concurrentAwaitingWrites ;
30
33
private long _writeTimingTimeoutTimestamp ;
31
34
32
- public TimeoutControl ( ITimeoutHandler timeoutHandler )
35
+ public TimeoutControl ( ITimeoutHandler timeoutHandler , long tickFrequency )
33
36
{
34
37
_timeoutHandler = timeoutHandler ;
38
+ _tickFrequency = tickFrequency ;
39
+ _heartbeatIntervalTicks = Heartbeat . Interval . ToTicks ( _tickFrequency ) ;
35
40
}
36
41
37
42
public TimeoutReason TimerReason { get ; private set ; }
@@ -43,9 +48,9 @@ internal void Initialize(long nowTicks)
43
48
_lastTimestamp = nowTicks ;
44
49
}
45
50
46
- public void Tick ( DateTimeOffset now )
51
+ public void Tick ( long now )
47
52
{
48
- var timestamp = now . Ticks ;
53
+ var timestamp = now ;
49
54
50
55
CheckForTimeout ( timestamp ) ;
51
56
CheckForReadDataRateTimeout ( timestamp ) ;
@@ -108,13 +113,13 @@ private void CheckForReadDataRateTimeout(long timestamp)
108
113
109
114
// Assume overly long tick intervals are the result of server resource starvation.
110
115
// Don't count extra time between ticks against the rate limit.
111
- _readTimingElapsedTicks += Math . Min ( timestamp - _lastTimestamp , Heartbeat . Interval . Ticks ) ;
116
+ _readTimingElapsedTicks += Math . Min ( timestamp - _lastTimestamp , _heartbeatIntervalTicks ) ;
112
117
113
118
Debug . Assert ( _minReadRate != null ) ;
114
119
115
- if ( _minReadRate . BytesPerSecond > 0 && _readTimingElapsedTicks > _minReadRate . GracePeriod . Ticks )
120
+ if ( _minReadRate . BytesPerSecond > 0 && _readTimingElapsedTicks > _minReadRateGracePeriodTicks )
116
121
{
117
- var elapsedSeconds = ( double ) _readTimingElapsedTicks / TimeSpan . TicksPerSecond ;
122
+ var elapsedSeconds = ( double ) _readTimingElapsedTicks / _tickFrequency ;
118
123
var rate = _readTimingBytesRead / elapsedSeconds ;
119
124
120
125
timeout = rate < _minReadRate . BytesPerSecond && ! Debugger . IsAttached ;
@@ -145,7 +150,7 @@ private void CheckForWriteDataRateTimeout(long timestamp)
145
150
{
146
151
// Assume overly long tick intervals are the result of server resource starvation.
147
152
// Don't count extra time between ticks against the rate limit.
148
- var extraTimeForTick = timestamp - _lastTimestamp - Heartbeat . Interval . Ticks ;
153
+ var extraTimeForTick = timestamp - _lastTimestamp - _heartbeatIntervalTicks ;
149
154
150
155
if ( extraTimeForTick > 0 )
151
156
{
@@ -186,7 +191,7 @@ private void AssignTimeout(long ticks, TimeoutReason timeoutReason)
186
191
TimerReason = timeoutReason ;
187
192
188
193
// Add Heartbeat.Interval since this can be called right before the next heartbeat.
189
- Interlocked . Exchange ( ref _timeoutTimestamp , Interlocked . Read ( ref _lastTimestamp ) + ticks + Heartbeat . Interval . Ticks ) ;
194
+ Interlocked . Exchange ( ref _timeoutTimestamp , Interlocked . Read ( ref _lastTimestamp ) + ticks + _heartbeatIntervalTicks ) ;
190
195
}
191
196
192
197
public void InitializeHttp2 ( InputFlowControl connectionInputFlowControl )
@@ -202,6 +207,7 @@ public void StartRequestBody(MinDataRate minRate)
202
207
Debug . Assert ( _concurrentIncompleteRequestBodies == 0 || minRate == _minReadRate , "Multiple simultaneous read data rates are not supported." ) ;
203
208
204
209
_minReadRate = minRate ;
210
+ _minReadRateGracePeriodTicks = minRate . GracePeriod . ToTicks ( _tickFrequency ) ;
205
211
_concurrentIncompleteRequestBodies ++ ;
206
212
207
213
if ( _concurrentIncompleteRequestBodies == 1 )
@@ -282,14 +288,14 @@ public void BytesWrittenToBuffer(MinDataRate minRate, long count)
282
288
lock ( _writeTimingLock )
283
289
{
284
290
// Add Heartbeat.Interval since this can be called right before the next heartbeat.
285
- var currentTimeUpperBound = Interlocked . Read ( ref _lastTimestamp ) + Heartbeat . Interval . Ticks ;
286
- var ticksToCompleteWriteAtMinRate = TimeSpan . FromSeconds ( count / minRate . BytesPerSecond ) . Ticks ;
291
+ var currentTimeUpperBound = Interlocked . Read ( ref _lastTimestamp ) + _heartbeatIntervalTicks ;
292
+ var ticksToCompleteWriteAtMinRate = TimeSpan . FromSeconds ( count / minRate . BytesPerSecond ) . ToTicks ( _tickFrequency ) ;
287
293
288
294
// If ticksToCompleteWriteAtMinRate is less than the configured grace period,
289
295
// allow that write to take up to the grace period to complete. Only add the grace period
290
296
// to the current time and not to any accumulated timeout.
291
297
var singleWriteTimeoutTimestamp = currentTimeUpperBound + Math . Max (
292
- minRate . GracePeriod . Ticks ,
298
+ minRate . GracePeriod . ToTicks ( _tickFrequency ) ,
293
299
ticksToCompleteWriteAtMinRate ) ;
294
300
295
301
// Don't penalize a connection for completing previous writes more quickly than required.
@@ -316,7 +322,7 @@ void IConnectionTimeoutFeature.SetTimeout(TimeSpan timeSpan)
316
322
throw new InvalidOperationException ( CoreStrings . ConcurrentTimeoutsNotSupported ) ;
317
323
}
318
324
319
- SetTimeout ( timeSpan . Ticks , TimeoutReason . TimeoutFeature ) ;
325
+ SetTimeout ( timeSpan . ToTicks ( _tickFrequency ) , TimeoutReason . TimeoutFeature ) ;
320
326
}
321
327
322
328
void IConnectionTimeoutFeature . ResetTimeout ( TimeSpan timeSpan )
@@ -326,13 +332,13 @@ void IConnectionTimeoutFeature.ResetTimeout(TimeSpan timeSpan)
326
332
throw new ArgumentException ( CoreStrings . PositiveFiniteTimeSpanRequired , nameof ( timeSpan ) ) ;
327
333
}
328
334
329
- ResetTimeout ( timeSpan . Ticks , TimeoutReason . TimeoutFeature ) ;
335
+ ResetTimeout ( timeSpan . ToTicks ( _tickFrequency ) , TimeoutReason . TimeoutFeature ) ;
330
336
}
331
337
332
338
public long GetResponseDrainDeadline ( long ticks , MinDataRate minRate )
333
339
{
334
340
// On grace period overflow, use max value.
335
- var gracePeriod = ticks + minRate . GracePeriod . Ticks ;
341
+ var gracePeriod = ticks + minRate . GracePeriod . ToTicks ( _tickFrequency ) ;
336
342
gracePeriod = gracePeriod >= 0 ? gracePeriod : long . MaxValue ;
337
343
338
344
return Math . Max ( _writeTimingTimeoutTimestamp , gracePeriod ) ;
0 commit comments