Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions eng/Version.Details.xml
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
<Dependencies>
<ProductDependencies>
<Dependency Name="Microsoft.NETCore.Runtime.CoreCLR" Version="3.0.0-preview6.19279.4">
<Dependency Name="Microsoft.NETCore.Runtime.CoreCLR" Version="3.0.0-preview6.19280.2">
<Uri>https://github.com/dotnet/coreclr</Uri>
<Sha>42d8e40e469cf00128e0cfa48f24297afa13c36f</Sha>
<Sha>fa8383fb28be945cae900a5579afd5920f274fd4</Sha>
</Dependency>
<Dependency Name="Microsoft.NETCore.ILAsm" Version="3.0.0-preview6.19279.4">
<Dependency Name="Microsoft.NETCore.ILAsm" Version="3.0.0-preview6.19280.2">
<Uri>https://github.com/dotnet/coreclr</Uri>
<Sha>42d8e40e469cf00128e0cfa48f24297afa13c36f</Sha>
<Sha>fa8383fb28be945cae900a5579afd5920f274fd4</Sha>
</Dependency>
<Dependency Name="Microsoft.NET.Sdk.IL" Version="3.0.0-preview6.19279.4">
<Dependency Name="Microsoft.NET.Sdk.IL" Version="3.0.0-preview6.19280.2">
<Uri>https://github.com/dotnet/coreclr</Uri>
<Sha>42d8e40e469cf00128e0cfa48f24297afa13c36f</Sha>
<Sha>fa8383fb28be945cae900a5579afd5920f274fd4</Sha>
</Dependency>
</ProductDependencies>
<ToolsetDependencies>
Expand Down
4 changes: 2 additions & 2 deletions eng/Versions.props
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@
<MicrosoftNETCoreDotNetHostPackageVersion>3.0.0-preview6-27729-07</MicrosoftNETCoreDotNetHostPackageVersion>
<MicrosoftNETCoreDotNetHostPolicyPackageVersion>3.0.0-preview6-27729-07</MicrosoftNETCoreDotNetHostPolicyPackageVersion>
<!-- Coreclr dependencies -->
<MicrosoftNETCoreILAsmPackageVersion>3.0.0-preview6.19279.4</MicrosoftNETCoreILAsmPackageVersion>
<MicrosoftNETCoreRuntimeCoreCLRPackageVersion>3.0.0-preview6.19279.4</MicrosoftNETCoreRuntimeCoreCLRPackageVersion>
<MicrosoftNETCoreILAsmPackageVersion>3.0.0-preview6.19280.2</MicrosoftNETCoreILAsmPackageVersion>
<MicrosoftNETCoreRuntimeCoreCLRPackageVersion>3.0.0-preview6.19280.2</MicrosoftNETCoreRuntimeCoreCLRPackageVersion>
<!-- Corefx dependencies -->
<MicrosoftNETCorePlatformsPackageVersion>3.0.0-preview6.19279.8</MicrosoftNETCorePlatformsPackageVersion>
<runtimenativeSystemIOPortsPackageVersion>4.6.0-preview6.19279.8</runtimenativeSystemIOPortsPackageVersion>
Expand Down
2 changes: 1 addition & 1 deletion global.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@
"Microsoft.DotNet.Arcade.Sdk": "1.0.0-beta.19279.5",
"Microsoft.DotNet.Helix.Sdk": "2.0.0-beta.19279.5",
"FIX-85B6-MERGE-9C38-CONFLICT": "1.0.0",
"Microsoft.NET.Sdk.IL": "3.0.0-preview6.19279.4"
"Microsoft.NET.Sdk.IL": "3.0.0-preview6.19280.2"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -179,4 +179,4 @@ public bool GetProxyForUrl(
return useProxy;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ internal sealed partial class Http2Connection : HttpConnectionBase, IDisposable
private int _initialWindowSize;
private int _maxConcurrentStreams;
private int _pendingWindowUpdate;
private int _idleSinceTickCount;
private long _idleSinceTickCount;
private int _pendingWriters;

private bool _disposed;
Expand Down Expand Up @@ -1138,7 +1138,7 @@ private void Abort(Exception abortException)
}

/// <summary>Gets whether the connection exceeded any of the connection limits.</summary>
/// <param name="nowTicks">The current tick count. Passed in to amortize the cost of calling Environment.TickCount.</param>
/// <param name="nowTicks">The current tick count. Passed in to amortize the cost of calling Environment.TickCount64.</param>
/// <param name="connectionLifetime">How long a connection can be open to be considered reusable.</param>
/// <param name="connectionIdleTimeout">How long a connection can have been idle in the pool to be considered reusable.</param>
/// <returns>
Expand All @@ -1149,7 +1149,7 @@ private void Abort(Exception abortException)
/// the nature of connection pooling.
/// </returns>

public bool IsExpired(int nowTicks,
public bool IsExpired(long nowTicks,
TimeSpan connectionLifetime,
TimeSpan connectionIdleTimeout)

Expand All @@ -1162,9 +1162,9 @@ public bool IsExpired(int nowTicks,
// Check idle timeout when there are not pending requests for a while.
if ((connectionIdleTimeout != Timeout.InfiniteTimeSpan) &&
(_httpStreams.Count == 0) &&
((uint)(nowTicks - _idleSinceTickCount) > connectionIdleTimeout.TotalMilliseconds))
((nowTicks - _idleSinceTickCount) > connectionIdleTimeout.TotalMilliseconds))
{
if (NetEventSource.IsEnabled) Trace($"Connection no longer usable. Idle {TimeSpan.FromMilliseconds((uint)(nowTicks - _idleSinceTickCount))} > {connectionIdleTimeout}.");
if (NetEventSource.IsEnabled) Trace($"Connection no longer usable. Idle {TimeSpan.FromMilliseconds((nowTicks - _idleSinceTickCount))} > {connectionIdleTimeout}.");

return true;
}
Expand Down Expand Up @@ -1448,7 +1448,7 @@ private void RemoveStream(Http2Stream http2Stream)
if (_httpStreams.Count == 0)
{
// If this was last pending request, get timestamp so we can monitor idle time.
_idleSinceTickCount = Environment.TickCount;
_idleSinceTickCount = Environment.TickCount64;
}

if (_disposed)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,16 @@ internal abstract class HttpConnectionBase
public abstract Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken);
internal abstract void Trace(string message, string memberName = null);

private int CreationTickCount { get; } = Environment.TickCount;
private long CreationTickCount { get; } = Environment.TickCount64;

// Check if lifetime expired on connection.
public bool LifetimeExpired(int nowTicks, TimeSpan lifetime)
public bool LifetimeExpired(long nowTicks, TimeSpan lifetime)
{
bool expired =
lifetime != Timeout.InfiniteTimeSpan &&
(lifetime == TimeSpan.Zero || (uint)(nowTicks - CreationTickCount) > lifetime.TotalMilliseconds);
(lifetime == TimeSpan.Zero || (nowTicks - CreationTickCount) > lifetime.TotalMilliseconds);

if (expired && NetEventSource.IsEnabled) Trace($"Connection no longer usable. Alive {TimeSpan.FromMilliseconds((uint)(nowTicks - CreationTickCount))} > {lifetime}.");
if (expired && NetEventSource.IsEnabled) Trace($"Connection no longer usable. Alive {TimeSpan.FromMilliseconds((nowTicks - CreationTickCount))} > {lifetime}.");
return expired;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ private ValueTask<HttpConnection> GetOrReserveHttp11ConnectionAsync(Cancellation

TimeSpan pooledConnectionLifetime = _poolManager.Settings._pooledConnectionLifetime;
TimeSpan pooledConnectionIdleTimeout = _poolManager.Settings._pooledConnectionIdleTimeout;
int nowTicks = Environment.TickCount;
long nowTicks = Environment.TickCount64;
List<CachedConnection> list = _idleConnections;

// Try to find a usable cached connection.
Expand Down Expand Up @@ -340,7 +340,7 @@ private ValueTask<HttpConnection> GetOrReserveHttp11ConnectionAsync(Cancellation
if (http2Connection != null)
{
TimeSpan pooledConnectionLifetime = _poolManager.Settings._pooledConnectionLifetime;
if (http2Connection.LifetimeExpired(Environment.TickCount, pooledConnectionLifetime))
if (http2Connection.LifetimeExpired(Environment.TickCount64, pooledConnectionLifetime))
{
// Connection expired.
http2Connection.Dispose();
Expand Down Expand Up @@ -797,7 +797,7 @@ public void DecrementConnectionCount()
/// <param name="connection">The connection to return.</param>
public void ReturnConnection(HttpConnection connection)
{
bool lifetimeExpired = connection.LifetimeExpired(Environment.TickCount, _poolManager.Settings._pooledConnectionLifetime);
bool lifetimeExpired = connection.LifetimeExpired(Environment.TickCount64, _poolManager.Settings._pooledConnectionLifetime);

if (!lifetimeExpired)
{
Expand Down Expand Up @@ -915,7 +915,7 @@ public bool CleanCacheAndDisposeIfUnused()

// Get the current time. This is compared against each connection's last returned
// time to determine whether a connection is too old and should be closed.
int nowTicks = Environment.TickCount;
long nowTicks = Environment.TickCount64;
Http2Connection http2Connection = _http2Connection;

if (http2Connection != null)
Expand Down Expand Up @@ -1039,15 +1039,15 @@ private void Trace(string message, [CallerMemberName] string memberName = null)
/// <summary>The cached connection.</summary>
internal readonly HttpConnection _connection;
/// <summary>The last tick count at which the connection was used.</summary>
internal readonly int _returnedTickCount;
internal readonly long _returnedTickCount;

/// <summary>Initializes the cached connection and its associated metadata.</summary>
/// <param name="connection">The connection.</param>
public CachedConnection(HttpConnection connection)
{
Debug.Assert(connection != null);
_connection = connection;
_returnedTickCount = Environment.TickCount;
_returnedTickCount = Environment.TickCount64;
}

/// <summary>Gets whether the connection is currently usable.</summary>
Expand All @@ -1062,16 +1062,16 @@ public CachedConnection(HttpConnection connection)
/// the nature of connection pooling.
/// </returns>
public bool IsUsable(
int nowTicks,
long nowTicks,
TimeSpan pooledConnectionLifetime,
TimeSpan pooledConnectionIdleTimeout,
bool poll = false)
{
// Validate that the connection hasn't been idle in the pool for longer than is allowed.
if ((pooledConnectionIdleTimeout != Timeout.InfiniteTimeSpan) &&
((uint)(nowTicks - _returnedTickCount) > pooledConnectionIdleTimeout.TotalMilliseconds))
((nowTicks - _returnedTickCount) > pooledConnectionIdleTimeout.TotalMilliseconds))
{
if (NetEventSource.IsEnabled) _connection.Trace($"Connection no longer usable. Idle {TimeSpan.FromMilliseconds((uint)(nowTicks - _returnedTickCount))} > {pooledConnectionIdleTimeout}.");
if (NetEventSource.IsEnabled) _connection.Trace($"Connection no longer usable. Idle {TimeSpan.FromMilliseconds((nowTicks - _returnedTickCount))} > {pooledConnectionIdleTimeout}.");
return false;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,17 +64,6 @@ public HttpConnectionSettings CloneAndNormalize()
_cookieContainer = new CookieContainer();
}

// The implementation uses Environment.TickCount to track connection lifetimes, as Environment.TickCount
// is measurable faster than DateTime.UtcNow / Stopwatch.GetTimestamp, and we do it at least once per request.
// However, besides its lower resolution (which is fine for SocketHttpHandler's needs), due to being based on
// an Int32 rather than Int64, the difference between two tick counts is at most ~49 days. This means that
// specifying a connection idle or lifetime of greater than 49 days would cause it to never be reached. The
// chances of a connection being open anywhere near that long is close to zero, as is the chance that someone
// would choose to specify such a long timeout, but regardless, we avoid issues by capping the timeouts.
TimeSpan timeLimit = TimeSpan.FromDays(40); // something super long but significantly less than the 49 day limit
TimeSpan pooledConnectionLifetime = _pooledConnectionLifetime < timeLimit ? _pooledConnectionLifetime : timeLimit;
TimeSpan pooledConnectionIdleTimeout = _pooledConnectionIdleTimeout < timeLimit ? _pooledConnectionIdleTimeout : timeLimit;

return new HttpConnectionSettings()
{
_allowAutoRedirect = _allowAutoRedirect,
Expand All @@ -90,8 +79,8 @@ public HttpConnectionSettings CloneAndNormalize()
_maxResponseDrainSize = _maxResponseDrainSize,
_maxResponseDrainTime = _maxResponseDrainTime,
_maxResponseHeadersLength = _maxResponseHeadersLength,
_pooledConnectionLifetime = pooledConnectionLifetime,
_pooledConnectionIdleTimeout = pooledConnectionIdleTimeout,
_pooledConnectionLifetime = _pooledConnectionLifetime,
_pooledConnectionIdleTimeout = _pooledConnectionIdleTimeout,
_preAuthenticate = _preAuthenticate,
_properties = _properties,
_proxy = _proxy,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -670,6 +670,7 @@ public static partial class Environment
public static string SystemDirectory { get { throw null; } }
public static int SystemPageSize { get { throw null; } }
public static int TickCount { get { throw null; } }
public static long TickCount64 { get { throw null; } }
public static string UserDomainName { get { throw null; } }
public static bool UserInteractive { get { throw null; } }
public static string UserName { get { throw null; } }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public class EnvironmentTickCount
public void TickCountTest()
{
int start = Environment.TickCount;
HashSet<int> times = new HashSet<int>();
var times = new HashSet<int>();
Func<bool> test = () =>
{
int time = Environment.TickCount;
Expand All @@ -26,5 +26,21 @@ public void TickCountTest()
SpinWait.SpinUntil(test, TimeSpan.FromSeconds(1)) || test(),
$"TickCount did not increase after one second. start: {start}, values tested: {string.Join(", ", times.ToArray())}.");
}

[Fact]
public void TickCount64Test()
{
long start = Environment.TickCount64;
var times = new HashSet<long>();
Func<bool> test = () =>
{
long time = Environment.TickCount64;
times.Add(time);
return time - start > 0;
};
Assert.True(
SpinWait.SpinUntil(test, TimeSpan.FromSeconds(1)) || test(),
$"TickCount did not increase after one second. start: {start}, values tested: {string.Join(", ", times.ToArray())}.");
}
}
}