Skip to content

Commit 7441855

Browse files
committed
Don't use a GUID for request ID because it's slow:
- FastHttpRequestIdentifierFeature uses an incrementing long with an int seed - Everything is lazy so no computer incurred if ID is not asked for - Optimized routine to stringify the ID - #306
1 parent 1ef8474 commit 7441855

File tree

4 files changed

+107
-7
lines changed

4 files changed

+107
-7
lines changed
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.Threading;
6+
using Microsoft.AspNet.Http.Features;
7+
8+
namespace Microsoft.AspNet.Hosting.Internal
9+
{
10+
public class FastHttpRequestIdentifierFeature : IHttpRequestIdentifierFeature
11+
{
12+
private static readonly string _hexChars = "0123456789ABCDEF";
13+
// Seed the _requestId for this application instance with a random int
14+
private static long _requestId = new Random().Next();
15+
16+
private string _id = null;
17+
18+
public string TraceIdentifier
19+
{
20+
get
21+
{
22+
// Don't incur the cost of generating the request ID until it's asked for
23+
if (_id == null)
24+
{
25+
_id = GenerateRequestId(Interlocked.Increment(ref _requestId));
26+
}
27+
return _id;
28+
}
29+
set
30+
{
31+
_id = value;
32+
}
33+
}
34+
35+
private static string GenerateRequestId(long id)
36+
{
37+
// The following routine is ~33% faster than calling long.ToString() when testing in tight loops of
38+
// 1 million iterations.
39+
var charBuffer = new char[sizeof(long) * 2];
40+
charBuffer[0] = _hexChars[(int)(id >> 60) & 0x0f];
41+
charBuffer[1] = _hexChars[(int)(id >> 56) & 0x0f];
42+
charBuffer[2] = _hexChars[(int)(id >> 52) & 0x0f];
43+
charBuffer[3] = _hexChars[(int)(id >> 48) & 0x0f];
44+
charBuffer[4] = _hexChars[(int)(id >> 44) & 0x0f];
45+
charBuffer[5] = _hexChars[(int)(id >> 40) & 0x0f];
46+
charBuffer[6] = _hexChars[(int)(id >> 36) & 0x0f];
47+
charBuffer[7] = _hexChars[(int)(id >> 32) & 0x0f];
48+
charBuffer[8] = _hexChars[(int)(id >> 28) & 0x0f];
49+
charBuffer[9] = _hexChars[(int)(id >> 24) & 0x0f];
50+
charBuffer[10] = _hexChars[(int)(id >> 20) & 0x0f];
51+
charBuffer[11] = _hexChars[(int)(id >> 16) & 0x0f];
52+
charBuffer[12] = _hexChars[(int)(id >> 12) & 0x0f];
53+
charBuffer[13] = _hexChars[(int)(id >> 8) & 0x0f];
54+
charBuffer[14] = _hexChars[(int)(id >> 4) & 0x0f];
55+
charBuffer[15] = _hexChars[(int)(id >> 0) & 0x0f];
56+
57+
return new string(charBuffer);
58+
}
59+
}
60+
}

src/Microsoft.AspNet.Hosting/Internal/HostingEngine.cs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
using Microsoft.AspNet.Hosting.Startup;
1313
using Microsoft.AspNet.Http;
1414
using Microsoft.AspNet.Http.Features;
15-
using Microsoft.AspNet.Http.Features.Internal;
1615
using Microsoft.AspNet.Server.Features;
1716
using Microsoft.Dnx.Runtime;
1817
using Microsoft.Extensions.Configuration;
@@ -278,10 +277,7 @@ private string GetRequestIdentifier(HttpContext httpContext)
278277
var requestIdentifierFeature = httpContext.Features.Get<IHttpRequestIdentifierFeature>();
279278
if (requestIdentifierFeature == null)
280279
{
281-
requestIdentifierFeature = new HttpRequestIdentifierFeature()
282-
{
283-
TraceIdentifier = Guid.NewGuid().ToString()
284-
};
280+
requestIdentifierFeature = new FastHttpRequestIdentifierFeature();
285281
httpContext.Features.Set(requestIdentifierFeature);
286282
}
287283

test/Microsoft.AspNet.Hosting.Tests/HostingEngineTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@ public void HostingEngine_CreatesDefaultRequestIdentifierFeature_IfNotPresent()
305305

306306
// Assert
307307
Assert.NotNull(httpContext);
308-
Assert.IsType<HttpRequestIdentifierFeature>(httpContext.Features.Get<IHttpRequestIdentifierFeature>());
308+
Assert.IsType<FastHttpRequestIdentifierFeature>(httpContext.Features.Get<IHttpRequestIdentifierFeature>());
309309
}
310310

311311
[Fact]
@@ -328,7 +328,7 @@ public void Hosting_CreatesDefaultRequestIdentifierFeature_IfNotPresent_ForImmut
328328

329329
// Assert
330330
Assert.NotNull(httpContext);
331-
Assert.IsType<HttpRequestIdentifierFeature>(httpContext.Features.Get<IHttpRequestIdentifierFeature>());
331+
Assert.IsType<FastHttpRequestIdentifierFeature>(httpContext.Features.Get<IHttpRequestIdentifierFeature>());
332332
}
333333

334334
[Fact]
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using Microsoft.AspNet.Hosting.Internal;
5+
using Xunit;
6+
7+
namespace Microsoft.AspNet.Hosting.Tests.Internal
8+
{
9+
public class FastHttpRequestIdentifierFeatureTests
10+
{
11+
[Fact]
12+
public void TraceIdentifier_ReturnsId()
13+
{
14+
var feature = new FastHttpRequestIdentifierFeature();
15+
16+
var id = feature.TraceIdentifier;
17+
18+
Assert.NotNull(id);
19+
}
20+
21+
[Fact]
22+
public void TraceIdentifier_ReturnsStableId()
23+
{
24+
var feature = new FastHttpRequestIdentifierFeature();
25+
26+
var id1 = feature.TraceIdentifier;
27+
var id2 = feature.TraceIdentifier;
28+
29+
Assert.Equal(id1, id2);
30+
}
31+
32+
[Fact]
33+
public void TraceIdentifier_ReturnsUniqueIdForDifferentInstances()
34+
{
35+
var feature1 = new FastHttpRequestIdentifierFeature();
36+
var feature2 = new FastHttpRequestIdentifierFeature();
37+
38+
var id1 = feature1.TraceIdentifier;
39+
var id2 = feature2.TraceIdentifier;
40+
41+
Assert.NotEqual(id1, id2);
42+
}
43+
}
44+
}

0 commit comments

Comments
 (0)