Merge pull request #1 from Microsoft/dev/lemejia/FirstCommit
Initial Commit
This commit is contained in:
Коммит
7c4addce2c
|
@ -0,0 +1,31 @@
|
||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio 15
|
||||||
|
VisualStudioVersion = 15.0.27130.2027
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CorrelationVector", "Microsoft.CorrelationVector\Microsoft.CorrelationVector.csproj", "{6F211D1F-0E72-4C05-9B9B-4DEC3AF01B38}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CorrelationVector.UnitTests", "Microsoft.CorrelationVector.UnitTests\Microsoft.CorrelationVector.UnitTests.csproj", "{EBE497F1-56EA-4BEA-B834-AEEE261BA6B8}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{6F211D1F-0E72-4C05-9B9B-4DEC3AF01B38}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{6F211D1F-0E72-4C05-9B9B-4DEC3AF01B38}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{6F211D1F-0E72-4C05-9B9B-4DEC3AF01B38}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{6F211D1F-0E72-4C05-9B9B-4DEC3AF01B38}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{EBE497F1-56EA-4BEA-B834-AEEE261BA6B8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{EBE497F1-56EA-4BEA-B834-AEEE261BA6B8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{EBE497F1-56EA-4BEA-B834-AEEE261BA6B8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{EBE497F1-56EA-4BEA-B834-AEEE261BA6B8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {0421635B-CD1D-4001-8D21-FA1A33F7B83E}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
|
@ -0,0 +1,115 @@
|
||||||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
|
using Microsoft.CorrelationVector;
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
|
||||||
|
namespace Microsoft.CorrelationVector.UnitTests
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class CorrelationVectorTests
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void SimpleCreateCorrelationVectorTest()
|
||||||
|
{
|
||||||
|
var correlationVector = new CorrelationVector();
|
||||||
|
var splitVector = correlationVector.Value.Split('.');
|
||||||
|
|
||||||
|
Assert.AreEqual(2, splitVector.Length, "Correlation Vector should be created with two components separated by a '.'");
|
||||||
|
Assert.AreEqual(16, splitVector[0].Length, "Correlation Vector base should be 16 character long");
|
||||||
|
Assert.AreEqual("0", splitVector[1], "Correlation Vector extension should start with zero");
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void CreateV1CorrelationVectorTest()
|
||||||
|
{
|
||||||
|
var correlationVector = new CorrelationVector(CorrelationVectorVersion.V1);
|
||||||
|
var splitVector = correlationVector.Value.Split('.');
|
||||||
|
|
||||||
|
Assert.AreEqual(2, splitVector.Length, "Correlation Vector should be created with two components separated by a '.'");
|
||||||
|
Assert.AreEqual(16, splitVector[0].Length, "Correlation Vector base should be 16 character long");
|
||||||
|
Assert.AreEqual("0", splitVector[1], "Correlation Vector extension should start with zero");
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void CreateV2CorrelationVectorTest()
|
||||||
|
{
|
||||||
|
var correlationVector = new CorrelationVector(CorrelationVectorVersion.V2);
|
||||||
|
var splitVector = correlationVector.Value.Split('.');
|
||||||
|
|
||||||
|
Assert.AreEqual(2, splitVector.Length, "Correlation Vector should be created with two components separated by a '.'");
|
||||||
|
Assert.AreEqual(22, splitVector[0].Length, "Correlation Vector base should be 22 character long");
|
||||||
|
Assert.AreEqual("0", splitVector[1], "Correlation Vector extension should start with zero");
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void CreateCorrelationVectorFromGuidTest()
|
||||||
|
{
|
||||||
|
var guid = System.Guid.NewGuid();
|
||||||
|
var correlationVector = new CorrelationVector(guid);
|
||||||
|
var splitVector = correlationVector.Value.Split('.');
|
||||||
|
|
||||||
|
Assert.AreEqual(2, splitVector.Length, "Correlation Vector should be created with two components separated by a '.'");
|
||||||
|
Assert.AreEqual(22, splitVector[0].Length, "Correlation Vector base should be 22 character long");
|
||||||
|
Assert.AreEqual("0", splitVector[1], "Correlation Vector extension should start with zero");
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ParseCorrelationVectorV1Test()
|
||||||
|
{
|
||||||
|
var correlationVector = CorrelationVector.Parse("ifCuqpnwiUimg7Pk.1");
|
||||||
|
var splitVector = correlationVector.Value.Split('.');
|
||||||
|
|
||||||
|
Assert.AreEqual("ifCuqpnwiUimg7Pk", splitVector[0], "Correlation Vector base was not parsed properly");
|
||||||
|
Assert.AreEqual("1", splitVector[1], "Correlation Vector extension was not parsed properly");
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ParseCorrelationVectorV2Test()
|
||||||
|
{
|
||||||
|
var correlationVector = CorrelationVector.Parse("Y58xO9ov0kmpPvkiuzMUVA.3.4.5");
|
||||||
|
var splitVector = correlationVector.Value.Split('.');
|
||||||
|
|
||||||
|
Assert.AreEqual(4, splitVector.Length, "Correlation Vector was not parsed properly");
|
||||||
|
Assert.AreEqual("Y58xO9ov0kmpPvkiuzMUVA", splitVector[0], "Correlation Vector base was not parsed properly");
|
||||||
|
Assert.AreEqual("3", splitVector[1], "Correlation Vector extension was not parsed properly");
|
||||||
|
Assert.AreEqual("4", splitVector[2], "Correlation Vector extension was not parsed properly");
|
||||||
|
Assert.AreEqual("5", splitVector[3], "Correlation Vector extension was not parsed properly");
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void SimpleIncrementCorrelationVectorTest()
|
||||||
|
{
|
||||||
|
var correlationVector = new CorrelationVector();
|
||||||
|
correlationVector.Increment();
|
||||||
|
var splitVector = correlationVector.Value.Split('.');
|
||||||
|
Assert.AreEqual("1", splitVector[1], "Correlation Vector extension should have been incremented by one");
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void SimpleExtendCorrelationVectorTest()
|
||||||
|
{
|
||||||
|
var correlationVector = new CorrelationVector();
|
||||||
|
var splitVector = correlationVector.Value.Split('.');
|
||||||
|
var vectorBase = splitVector[0];
|
||||||
|
var extension = splitVector[1];
|
||||||
|
|
||||||
|
correlationVector = CorrelationVector.Extend(correlationVector.Value);
|
||||||
|
splitVector = correlationVector.Value.Split('.');
|
||||||
|
|
||||||
|
Assert.AreEqual(3, splitVector.Length, "Correlation Vector should contain 3 components separated by a '.' after extension");
|
||||||
|
Assert.AreEqual(vectorBase, splitVector[0], "Correlation Vector base should contain the same base after extension");
|
||||||
|
Assert.AreEqual(extension, splitVector[1], "Correlation Vector should preserve original ");
|
||||||
|
Assert.AreEqual("0", splitVector[2], "Correlation Vector new extension should start with zero");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ValidateCreationTest()
|
||||||
|
{
|
||||||
|
CorrelationVector.ValidateCorrelationVectorDuringCreation = true;
|
||||||
|
var correlationVector = new CorrelationVector();
|
||||||
|
correlationVector.Increment();
|
||||||
|
var splitVector = correlationVector.Value.Split('.');
|
||||||
|
Assert.AreEqual("1", splitVector[1], "Correlation Vector extension should have been incremented by one");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||||
|
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0" />
|
||||||
|
<PackageReference Include="MSTest.TestAdapter" Version="1.2.0" />
|
||||||
|
<PackageReference Include="MSTest.TestFramework" Version="1.2.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Microsoft.CorrelationVector\Microsoft.CorrelationVector.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
|
@ -0,0 +1,350 @@
|
||||||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Globalization;
|
||||||
|
|
||||||
|
namespace Microsoft.CorrelationVector
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// This class represents a lightweight vector for identifying and measuring
|
||||||
|
/// causality.
|
||||||
|
/// </summary>
|
||||||
|
public sealed partial class CorrelationVector : MarshalByRefObject
|
||||||
|
{
|
||||||
|
private const byte MaxVectorLength = 63;
|
||||||
|
private const byte MaxVectorLengthV2 = 127;
|
||||||
|
private const byte BaseLength = 16;
|
||||||
|
private const byte BaseLengthV2 = 22;
|
||||||
|
|
||||||
|
private readonly string baseVector = null;
|
||||||
|
|
||||||
|
private int extension = 0;
|
||||||
|
|
||||||
|
private static Random rng = new Random();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This is the header that should be used between services to pass the correlation
|
||||||
|
/// vector.
|
||||||
|
/// </summary>
|
||||||
|
public const string HeaderName = "MS-CV";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether or not to validate the correlation
|
||||||
|
/// vector on creation.
|
||||||
|
/// </summary>
|
||||||
|
public static bool ValidateCorrelationVectorDuringCreation { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new correlation vector by extending an existing value. This should be
|
||||||
|
/// done at the entry point of an operation.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="correlationVector">
|
||||||
|
/// Taken from the message header indicated by <see cref="HeaderName"/>.
|
||||||
|
/// </param>
|
||||||
|
/// <returns>A new correlation vector extended from the current vector.</returns>
|
||||||
|
public static CorrelationVector Extend(string correlationVector)
|
||||||
|
{
|
||||||
|
CorrelationVectorVersion version = CorrelationVector.InferVersion(
|
||||||
|
correlationVector, CorrelationVector.ValidateCorrelationVectorDuringCreation);
|
||||||
|
|
||||||
|
if (CorrelationVector.ValidateCorrelationVectorDuringCreation)
|
||||||
|
{
|
||||||
|
CorrelationVector.Validate(correlationVector, version);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new CorrelationVector(correlationVector, 0, version);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new correlation vector by applying the Spin operator to an existing value.
|
||||||
|
/// This should be done at the entry point of an operation.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="correlationVector">
|
||||||
|
/// Taken from the message header indicated by <see cref="HeaderName"/>.
|
||||||
|
/// </param>
|
||||||
|
/// <returns>A new correlation vector extended from the current vector.</returns>
|
||||||
|
public static CorrelationVector Spin(string correlationVector)
|
||||||
|
{
|
||||||
|
SpinParameters defaultParameters = new SpinParameters
|
||||||
|
{
|
||||||
|
Interval = SpinCounterInterval.Coarse,
|
||||||
|
Periodicity = SpinCounterPeriodicity.Short,
|
||||||
|
Entropy = SpinEntropy.Two
|
||||||
|
};
|
||||||
|
|
||||||
|
return CorrelationVector.Spin(correlationVector, defaultParameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new correlation vector by applying the Spin operator to an existing value.
|
||||||
|
/// This should be done at the entry point of an operation.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="correlationVector">
|
||||||
|
/// Taken from the message header indicated by <see cref="HeaderName"/>.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="parameters">
|
||||||
|
/// The parameters to use when applying the Spin operator.
|
||||||
|
/// </param>
|
||||||
|
/// <returns>A new correlation vector extended from the current vector.</returns>
|
||||||
|
public static CorrelationVector Spin(string correlationVector, SpinParameters parameters)
|
||||||
|
{
|
||||||
|
CorrelationVectorVersion version = CorrelationVector.InferVersion(
|
||||||
|
correlationVector, CorrelationVector.ValidateCorrelationVectorDuringCreation);
|
||||||
|
|
||||||
|
if (CorrelationVector.ValidateCorrelationVectorDuringCreation)
|
||||||
|
{
|
||||||
|
CorrelationVector.Validate(correlationVector, version);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] entropy = new byte[parameters.EntropyBytes];
|
||||||
|
rng.NextBytes(entropy);
|
||||||
|
|
||||||
|
ulong value = (ulong)(DateTime.UtcNow.Ticks >> parameters.TicksBitsToDrop);
|
||||||
|
for (int i = 0; i < parameters.EntropyBytes; i++)
|
||||||
|
{
|
||||||
|
value = (value << 8) | Convert.ToUInt64(entropy[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate a bitmask and mask the lower TotalBits in the value.
|
||||||
|
// The mask is generated by (1 << TotalBits) - 1. We need to handle the edge case
|
||||||
|
// when shifting 64 bits, as it wraps around.
|
||||||
|
value &= (parameters.TotalBits == 64 ? 0 : (ulong)1 << parameters.TotalBits) - 1;
|
||||||
|
|
||||||
|
string s = unchecked((uint)value).ToString();
|
||||||
|
if (parameters.TotalBits > 32)
|
||||||
|
{
|
||||||
|
s = string.Concat((value >> 32).ToString(), ".", s);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new CorrelationVector(string.Concat(correlationVector, ".", s), 0, version);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new correlation vector by parsing its string representation
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="correlationVector">correlationVector</param>
|
||||||
|
/// <returns>CorrelationVector</returns>
|
||||||
|
public static CorrelationVector Parse(string correlationVector)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(correlationVector))
|
||||||
|
{
|
||||||
|
int p = correlationVector.LastIndexOf('.');
|
||||||
|
if (p > 0)
|
||||||
|
{
|
||||||
|
int extension;
|
||||||
|
if (int.TryParse(correlationVector.Substring(p + 1), out extension) && extension >= 0)
|
||||||
|
{
|
||||||
|
return new CorrelationVector(correlationVector.Substring(0, p), extension, CorrelationVector.InferVersion(correlationVector, false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new CorrelationVector();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="CorrelationVector"/> class. This
|
||||||
|
/// should only be called when no correlation vector was found in the message
|
||||||
|
/// header.
|
||||||
|
/// </summary>
|
||||||
|
public CorrelationVector()
|
||||||
|
: this(CorrelationVectorVersion.V1)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="CorrelationVector"/> class of the
|
||||||
|
/// given implemenation version. This should only be called when no correlation
|
||||||
|
/// vector was found in the message header.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="version">The correlation vector implemenation version.</param>
|
||||||
|
public CorrelationVector(CorrelationVectorVersion version)
|
||||||
|
: this(CorrelationVector.GetUniqueValue(version), 0, version)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="CorrelationVector"/> class of the
|
||||||
|
/// V2 implemenation using the given <see cref="System.Guid"/> as the vector base.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="vectorBase">The <see cref="System.Guid"/> to use as a correlation
|
||||||
|
/// vector base.</param>
|
||||||
|
public CorrelationVector(Guid vectorBase)
|
||||||
|
: this(CorrelationVector.GetBaseFromGuid(vectorBase), 0, CorrelationVectorVersion.V2)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the value of the correlation vector as a string.
|
||||||
|
/// </summary>
|
||||||
|
public string Value
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return string.Concat(this.baseVector, ".", this.extension);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Increments the current extension by one. Do this before passing the value to an
|
||||||
|
/// outbound message header.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>
|
||||||
|
/// The new value as a string that you can add to the outbound message header
|
||||||
|
/// indicated by <see cref="HeaderName"/>.
|
||||||
|
/// </returns>
|
||||||
|
public string Increment()
|
||||||
|
{
|
||||||
|
int snapshot = 0;
|
||||||
|
int next = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
snapshot = this.extension;
|
||||||
|
if (snapshot == int.MaxValue)
|
||||||
|
{
|
||||||
|
return this.Value;
|
||||||
|
}
|
||||||
|
next = snapshot + 1;
|
||||||
|
int size = baseVector.Length + 1 + (int)Math.Log10(next) + 1;
|
||||||
|
if ((this.Version == CorrelationVectorVersion.V1 &&
|
||||||
|
size > CorrelationVector.MaxVectorLength) ||
|
||||||
|
(this.Version == CorrelationVectorVersion.V2 &&
|
||||||
|
size > CorrelationVector.MaxVectorLengthV2))
|
||||||
|
{
|
||||||
|
return this.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (snapshot != Interlocked.CompareExchange(ref this.extension, next, snapshot));
|
||||||
|
return string.Concat(this.baseVector, ".", next);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the version of the correlation vector implementation.
|
||||||
|
/// </summary>
|
||||||
|
public CorrelationVectorVersion Version
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
private set;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a string that represents the current object.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A string that represents the current object.</returns>
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return this.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether two instances of the <see cref="CorrelationVector"/> class
|
||||||
|
/// are equal.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="vector">
|
||||||
|
/// The correlation vector you want to compare with the current correlation vector.
|
||||||
|
/// </param>
|
||||||
|
/// <returns>
|
||||||
|
/// True if the specified correlation vector is equal to the current correlation
|
||||||
|
/// vector; otherwise, false.
|
||||||
|
/// </returns>
|
||||||
|
public bool Equals(CorrelationVector vector)
|
||||||
|
{
|
||||||
|
return string.Equals(this.Value, vector.Value, StringComparison.Ordinal);
|
||||||
|
}
|
||||||
|
|
||||||
|
private CorrelationVector(string baseVector, int extension, CorrelationVectorVersion version)
|
||||||
|
{
|
||||||
|
this.baseVector = baseVector;
|
||||||
|
this.extension = extension;
|
||||||
|
this.Version = version;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetBaseFromGuid(Guid guid)
|
||||||
|
{
|
||||||
|
byte[] bytes = guid.ToByteArray();
|
||||||
|
|
||||||
|
// Removes the base64 padding
|
||||||
|
return Convert.ToBase64String(bytes).Substring(0, CorrelationVector.BaseLengthV2);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetUniqueValue(CorrelationVectorVersion version)
|
||||||
|
{
|
||||||
|
if (CorrelationVectorVersion.V1 == version)
|
||||||
|
{
|
||||||
|
byte[] bytes = Guid.NewGuid().ToByteArray();
|
||||||
|
return Convert.ToBase64String(bytes, 0, 12);
|
||||||
|
}
|
||||||
|
else if (CorrelationVectorVersion.V2 == version)
|
||||||
|
{
|
||||||
|
return CorrelationVector.GetBaseFromGuid(Guid.NewGuid());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "Unsupported correlation vector version: {0}", version));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static CorrelationVectorVersion InferVersion(string correlationVector, bool reportErrors)
|
||||||
|
{
|
||||||
|
int index = correlationVector == null ? -1 : correlationVector.IndexOf('.');
|
||||||
|
|
||||||
|
if (CorrelationVector.BaseLength == index)
|
||||||
|
{
|
||||||
|
return CorrelationVectorVersion.V1;
|
||||||
|
}
|
||||||
|
else if (CorrelationVector.BaseLengthV2 == index)
|
||||||
|
{
|
||||||
|
return CorrelationVectorVersion.V2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, "Invalid correlation vector {0}", correlationVector));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Validate(string correlationVector, CorrelationVectorVersion version)
|
||||||
|
{
|
||||||
|
byte maxVectorLength;
|
||||||
|
byte baseLength;
|
||||||
|
|
||||||
|
if (CorrelationVectorVersion.V1 == version)
|
||||||
|
{
|
||||||
|
maxVectorLength = CorrelationVector.MaxVectorLength;
|
||||||
|
baseLength = CorrelationVector.BaseLength;
|
||||||
|
}
|
||||||
|
else if (CorrelationVectorVersion.V2 == version)
|
||||||
|
{
|
||||||
|
maxVectorLength = CorrelationVector.MaxVectorLengthV2;
|
||||||
|
baseLength = CorrelationVector.BaseLengthV2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "Unsupported correlation vector version: {0}", version));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(correlationVector) || correlationVector.Length > maxVectorLength)
|
||||||
|
{
|
||||||
|
throw new ArgumentException(string.Format(CultureInfo.InvariantCulture,
|
||||||
|
"The {0} correlation vector can not be null or bigger than {1} characters", version, maxVectorLength));
|
||||||
|
}
|
||||||
|
|
||||||
|
string[] parts = correlationVector.Split('.');
|
||||||
|
|
||||||
|
if (parts.Length < 2 || parts[0].Length != baseLength)
|
||||||
|
{
|
||||||
|
throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "Invalid correlation vector {0}. Invalid base value {1}", correlationVector, parts[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 1; i < parts.Length; i++)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
if (int.TryParse(parts[i], out result) == false || result < 0)
|
||||||
|
{
|
||||||
|
throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "Invalid correlation vector {0}. Invalid extension value {1}", correlationVector, parts[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
|
namespace Microsoft.CorrelationVector
|
||||||
|
{
|
||||||
|
public enum CorrelationVectorVersion
|
||||||
|
{
|
||||||
|
V1,
|
||||||
|
V2,
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
</Project>
|
|
@ -0,0 +1,170 @@
|
||||||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Microsoft.CorrelationVector
|
||||||
|
{
|
||||||
|
public enum SpinCounterInterval
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The coarse interval drops the 24 least significant bits in DateTime.Ticks
|
||||||
|
/// resulting in a counter that increments every 1.67 seconds.
|
||||||
|
/// </summary>
|
||||||
|
Coarse,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The fine interval drops the 16 least significant bits in DateTime.Ticks
|
||||||
|
/// resulting in a counter that increments every 6.5 milliseconds.
|
||||||
|
/// </summary>
|
||||||
|
Fine
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum SpinCounterPeriodicity
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Do not store a counter as part of the spin value.
|
||||||
|
/// </summary>
|
||||||
|
None,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The short periodicity stores the counter using 16 bits.
|
||||||
|
/// </summary>
|
||||||
|
Short,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The medium periodicity stores the counter using 24 bits.
|
||||||
|
/// </summary>
|
||||||
|
Medium,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The long periodicity stores the counter using 32 bits.
|
||||||
|
/// </summary>
|
||||||
|
Long
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum SpinEntropy
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Do not generate entropy as part of the spin value.
|
||||||
|
/// </summary>
|
||||||
|
None = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generate entropy using 8 bits.
|
||||||
|
/// </summary>
|
||||||
|
One = 1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generate entropy using 16 bits.
|
||||||
|
/// </summary>
|
||||||
|
Two = 2,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generate entropy using 24 bits.
|
||||||
|
/// </summary>
|
||||||
|
Three = 3,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generate entropy using 32 bits.
|
||||||
|
/// </summary>
|
||||||
|
Four = 4
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This class stores parameters used by the CorrelationVector Spin operator.
|
||||||
|
/// </summary>
|
||||||
|
public class SpinParameters : MarshalByRefObject
|
||||||
|
{
|
||||||
|
// Internal value for entropy bytes.
|
||||||
|
private int entropyBytes;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The interval (proportional to time) by which the counter increments.
|
||||||
|
/// </summary>
|
||||||
|
public SpinCounterInterval Interval { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// How frequently the counter wraps around to zero, as determined by the amount
|
||||||
|
/// of space to store the counter.
|
||||||
|
/// </summary>
|
||||||
|
public SpinCounterPeriodicity Periodicity { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The number of bytes to use for entropy. Valid values from a
|
||||||
|
/// minimum of 0 to a maximum of 4.
|
||||||
|
/// </summary>
|
||||||
|
public SpinEntropy Entropy
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return (SpinEntropy)this.entropyBytes;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
this.entropyBytes = (int)value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The number of least significant bits to drop in DateTime.Ticks when
|
||||||
|
/// computing the counter.
|
||||||
|
/// </summary>
|
||||||
|
internal int TicksBitsToDrop
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
switch (this.Interval)
|
||||||
|
{
|
||||||
|
case SpinCounterInterval.Coarse:
|
||||||
|
return 24;
|
||||||
|
|
||||||
|
case SpinCounterInterval.Fine:
|
||||||
|
return 16;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 24;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The number of bytes used to store the entropy.
|
||||||
|
/// </summary>
|
||||||
|
internal int EntropyBytes
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return this.entropyBytes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal int TotalBits
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
int counterBits;
|
||||||
|
switch (this.Periodicity)
|
||||||
|
{
|
||||||
|
case SpinCounterPeriodicity.None:
|
||||||
|
counterBits = 0;
|
||||||
|
break;
|
||||||
|
case SpinCounterPeriodicity.Short:
|
||||||
|
counterBits = 16;
|
||||||
|
break;
|
||||||
|
case SpinCounterPeriodicity.Medium:
|
||||||
|
counterBits = 24;
|
||||||
|
break;
|
||||||
|
case SpinCounterPeriodicity.Long:
|
||||||
|
counterBits = 32;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
counterBits = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return counterBits + this.EntropyBytes * 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Загрузка…
Ссылка в новой задаче