Skip to content

Instantly share code, notes, and snippets.

@jpv001
Forked from afifmohammed/SimpleFlakeTest.cs
Last active August 29, 2015 14:22
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jpv001/5ac3f73dff192bb512eb to your computer and use it in GitHub Desktop.
Save jpv001/5ac3f73dff192bb512eb to your computer and use it in GitHub Desktop.
void Main()
{
var d = new Dictionary<BigInteger, BigInteger>();
var t = DateTime.Now;
var howfar = 0;
var r = 0;
for (int x = 0; x < 100000; x++)
{
for (int i = 0; i < 10000000; i++)
{
try
{
d.Add(CreateFlake(t), i);
}
catch
{
if (howfar == 0) howfar = i;
if (i < howfar) howfar = i;
i = 10000000;
}
}
r++;
d.Clear();
}
r.Dump();
howfar.Dump();
}
// Define other methods and classes here
private static readonly DateTime DEFAULT_EPOCH = new DateTime(2000, 01, 01);
/// <summary>
/// The Epoch point in time from which the timestamp will be calculated.
/// </summary>
public DateTime Epoch { get; private set; }
/// <summary>
/// Creates a Flake object based on a given date and time that can be used as part of a distributed ID system.
/// </summary>
/// <returns>A Flake that wraps an underlying BigInteger value made up of 41 bits of timestamp data plus 23 bits of random bits to avoid collisions in a distributed system.</returns>
public virtual BigInteger CreateFlake(DateTime timestamp)
{
if (timestamp < this.Epoch)
{
throw new Exception("The timestamp cannot be earlier than the Epoch time being used.");
}
// 64-bit Id will be 41 bits of milliseconds + 23 bits random
var bigTicks = this.GetMillisecondsSinceEpoch(timestamp);
// Get some random bits
var saltBytes = this.GetRandomBytes(3);
// Convert the random bytes to a BigInteger so we can bit shift
var bigSalt = new BigInteger(saltBytes);
// We are going to bit-shift the two values so we end up with the
// correct number of bits in each value
bigSalt = BigInteger.Abs(bigSalt) >> 1; // Shift right to go from 24 bits to 23
bigTicks = bigTicks << 23; // Shift left to make room for the Salt
// Bitwise OR the bits together to get one big 64-bit string where the first 41 bits
// are the timestamp and the last 23 are the salt
var result = bigTicks | bigSalt;
// Create a new Flake of type T that will be returned
return (BigInteger)result;
}
/// <summary>
/// Calculates the number of milliseconds that have elapsed since the Epoch time.
/// </summary>
/// <param name="now">DateTime value after Epoch time.</param>
/// <returns>A BigInteger value representing the number of milliseconds since the Epoch time.</returns>
protected virtual BigInteger GetMillisecondsSinceEpoch(DateTime now)
{
var millisecondsSinceEpoch = (now - this.Epoch).TotalMilliseconds;
var bigMillisecondsSinceEpoch = new BigInteger(millisecondsSinceEpoch);
return bigMillisecondsSinceEpoch;
}
/// <summary>
/// Generates a random set of bytes.
/// </summary>
/// <param name="count">The number of bytes to randomly generate.</param>
/// <returns>An array of randomized bytes of the given length.</returns>
protected virtual byte[] GetRandomBytes(int count)
{
var crypto = new CryptoRandom();
var intValue = crypto.Next();
byte[] intBytes = BitConverter.GetBytes(intValue);
if (BitConverter.IsLittleEndian)
Array.Reverse(intBytes);
return intBytes;
}
class CryptoRandom : RandomNumberGenerator
{
private static RandomNumberGenerator r;
public CryptoRandom()
{
r = RandomNumberGenerator.Create();
}
public override void GetBytes(byte[] buffer)
{
r.GetBytes(buffer);
}
public double NextDouble()
{
var b = new byte[4];
r.GetBytes(b);
return (double)BitConverter.ToUInt32(b, 0) / UInt32.MaxValue;
}
public int Next(int minValue, int maxValue)
{
return (int)Math.Round(NextDouble() * (maxValue - minValue - 1)) + minValue;
}
public int Next()
{
return Next(0, Int32.MaxValue);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment