private CorrelationVector(string baseVector, int extension, CorrelationVectorVersion version, bool immutable) { this.BaseVector = baseVector; this.extension = extension; this.Version = version; this.immutable = immutable || CorrelationVector.IsOversized(baseVector, extension, version); }
/// <summary> /// Gets the value of the correlation vector base encoded as a <see cref="Guid"/>. /// </summary> /// <returns>The <see cref="Guid"/> value of the encoded vector base.</returns> public static Guid GetBaseAsGuid(this CorrelationVector correlationVector) { if (correlationVector.Version == CorrelationVectorVersion.V1) { throw new InvalidOperationException("Cannot convert a V1 correlation vector base to a guid."); } if (CorrelationVector.ValidateCorrelationVectorDuringCreation) { // In order to reliably convert a V2 vector base to a guid, the four least significant bits of the last // base64 content-bearing 6-bit block must be zeros. // There are four such base64 characters so we can easily detect whether this condition is true. // A - 00 0000 // Q - 01 0000 // g - 10 0000 // w - 11 0000 char lastChar = correlationVector.BaseVector[CorrelationVector.BaseLengthV2 - 1]; if (lastChar != 'A' && lastChar != 'Q' && lastChar != 'g' && lastChar != 'w') { throw new InvalidOperationException( "The four least significant bits of the base64 encoded vector base must be zeros to reliably convert to a guid."); } } return(new Guid(Convert.FromBase64String(correlationVector.BaseVector + "=="))); }
/// <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() { if (this.immutable) { return(this.Value); } int snapshot = 0; int next = 0; do { snapshot = this.extension; if (snapshot == int.MaxValue) { return(this.Value); } next = snapshot + 1; if (CorrelationVector.IsOversized(this.BaseVector, next, this.Version)) { this.immutable = true; return(this.Value); } }while (snapshot != Interlocked.CompareExchange(ref this.extension, next, snapshot)); return(string.Concat(this.BaseVector, ".", next)); }
/// <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) { if (CorrelationVector.IsImmutable(correlationVector)) { return(CorrelationVector.Parse(correlationVector)); } 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); } string baseVector = string.Concat(correlationVector, ".", s); if (CorrelationVector.IsOversized(baseVector, 0, version)) { return(CorrelationVector.Parse(correlationVector + CorrelationVector.TerminationSign)); } return(new CorrelationVector(baseVector, 0, version, false)); }
/// <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('.'); bool immutable = CorrelationVector.IsImmutable(correlationVector); if (p > 0) { string extensionValue = immutable ? correlationVector.Substring(p + 1, correlationVector.Length - p - 1 - CorrelationVector.TerminationSign.Length) : correlationVector.Substring(p + 1); int extension; if (int.TryParse(extensionValue, out extension) && extension >= 0) { return(new CorrelationVector(correlationVector.Substring(0, p), extension, CorrelationVector.InferVersion(correlationVector, false), immutable)); } } } return(new CorrelationVector()); }
/// <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) { if (CorrelationVector.IsImmutable(correlationVector)) { return(CorrelationVector.Parse(correlationVector)); } CorrelationVectorVersion version = CorrelationVector.InferVersion( correlationVector, CorrelationVector.ValidateCorrelationVectorDuringCreation); if (CorrelationVector.ValidateCorrelationVectorDuringCreation) { CorrelationVector.Validate(correlationVector, version); } if (CorrelationVector.IsOversized(correlationVector, 0, version)) { return(CorrelationVector.Parse(correlationVector + CorrelationVector.TerminationSign)); } return(new CorrelationVector(correlationVector, 0, version, false)); }
/// <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)); }
/// <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, false) { }