Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

made the clock sequence of the TimeUUID generator in the GuidGenerato…

…r class random and static until changed, since it didn't have to change with each new request according to RFC 4122 found this while trying to hunt down a non-issue with issue #39 related to the use of TimeUUID in composite keys
  • Loading branch information...
commit 9ad51b3abf89d99b617acbea305a256556b0e4ea 1 parent 6851535
@nberardi nberardi authored
View
42 src/GuidGenerator.cs
@@ -3,6 +3,10 @@
namespace FluentCassandra
{
+ /// <summary>
+ /// Used for generating UUID based on RFC 4122.
+ /// </summary>
+ /// <seealso href="http://www.ietf.org/rfc/rfc4122.txt">RFC 4122 - A Universally Unique IDentifier (UUID) URN Namespace</seealso>
public static partial class GuidGenerator
{
// number of bytes in guid
@@ -26,15 +30,18 @@ public static partial class GuidGenerator
// offset to move from 1/1/0001, which is 0-time for .NET, to gregorian 0-time of 10/15/1582
private static readonly DateTimeOffset GregorianCalendarStart = new DateTimeOffset(1582, 10, 15, 0, 0, 0, TimeSpan.Zero);
- // random node that is 16 bytes
- private static readonly byte[] RandomNode;
+ // random clock sequence and node
+ public static byte[] DefaultClockSequence { get; set; }
+ public static byte[] DefaultNode { get; set; }
static GuidGenerator()
{
- RandomNode = new byte[6];
+ DefaultClockSequence = new byte[2];
+ DefaultNode = new byte[6];
var random = new Random();
- random.NextBytes(RandomNode);
+ random.NextBytes(DefaultClockSequence);
+ random.NextBytes(DefaultNode);
}
public static GuidVersion GetVersion(this Guid guid)
@@ -77,36 +84,47 @@ public static DateTime GetUtcDateTime(Guid guid)
public static Guid GenerateTimeBasedGuid()
{
- return GenerateTimeBasedGuid(DateTimePrecise.UtcNowOffset, RandomNode);
+ return GenerateTimeBasedGuid(DateTimePrecise.UtcNowOffset, DefaultClockSequence, DefaultNode);
}
public static Guid GenerateTimeBasedGuid(DateTime dateTime)
{
- return GenerateTimeBasedGuid(dateTime, RandomNode);
+ return GenerateTimeBasedGuid(dateTime, DefaultClockSequence, DefaultNode);
}
public static Guid GenerateTimeBasedGuid(DateTimeOffset dateTime)
{
- return GenerateTimeBasedGuid(dateTime, RandomNode);
+ return GenerateTimeBasedGuid(dateTime, DefaultClockSequence, DefaultNode);
}
- public static Guid GenerateTimeBasedGuid(DateTime dateTime, byte[] node)
+ public static Guid GenerateTimeBasedGuid(DateTime dateTime, byte[] clockSequence, byte[] node)
{
- return GenerateTimeBasedGuid(new DateTimeOffset(dateTime), node);
+ return GenerateTimeBasedGuid(new DateTimeOffset(dateTime), clockSequence, node);
}
- public static Guid GenerateTimeBasedGuid(DateTimeOffset dateTime, byte[] node)
+ public static Guid GenerateTimeBasedGuid(DateTimeOffset dateTime, byte[] clockSequence, byte[] node)
{
+ if (clockSequence == null)
+ throw new ArgumentNullException("clockSequence");
+
+ if (node == null)
+ throw new ArgumentNullException("node");
+
+ if (clockSequence.Length != 2)
+ throw new ArgumentOutOfRangeException("clockSequence", "The clockSequence must be 2 bytes.");
+
+ if (node.Length != 6)
+ throw new ArgumentOutOfRangeException("node", "The node must be 6 bytes.");
+
long ticks = (dateTime - GregorianCalendarStart).Ticks;
byte[] guid = new byte[ByteArraySize];
- byte[] clockSequenceBytes = BitConverter.GetBytes(Convert.ToInt16(Environment.TickCount % Int16.MaxValue));
byte[] timestamp = BitConverter.GetBytes(ticks);
// copy node
Array.Copy(node, 0, guid, NodeByte, Math.Min(6, node.Length));
// copy clock sequence
- Array.Copy(clockSequenceBytes, 0, guid, GuidClockSequenceByte, Math.Min(2, clockSequenceBytes.Length));
+ Array.Copy(clockSequence, 0, guid, GuidClockSequenceByte, Math.Min(2, clockSequence.Length));
// copy timestamp
Array.Copy(timestamp, 0, guid, TimestampByte, Math.Min(8, timestamp.Length));
View
60 test/FluentCassandra.Tests/Bugs/Issue39CompositeTypeAsKey.cs
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
-using System.Text;
using FluentCassandra.Types;
using Xunit;
@@ -23,7 +22,7 @@ public void Dispose()
}
[Fact]
- public void Test()
+ public void Test_Composite2()
{
// arrange
var keyspace = _db.Keyspace;
@@ -37,17 +36,17 @@ public void Test()
DefaultColumnValueType = CassandraType.BytesType
});
- InsertMarketData("TT", "A", new Dictionary<string, string> { { "Status", "Working" } });
+ InsertData2("TT", "A", new Dictionary<string, string> { { "Status", "Working" } });
// act
- var actual = GetData("TT", "A", "Status");
+ var actual = GetData2("TT", "A", "Status");
// assert
Assert.NotNull(actual);
Assert.Equal(1, actual.Columns.Count);
}
- public void InsertMarketData(string key1, string key2, Dictionary<string, string> values)
+ public void InsertData2(string key1, string key2, Dictionary<string, string> values)
{
var productFamily = _db.GetColumnFamily("Data");
var key = new CompositeType<AsciiType, AsciiType>(key1, key2);
@@ -61,12 +60,61 @@ public void InsertMarketData(string key1, string key2, Dictionary<string, string
_db.SaveChanges();
}
- public FluentColumnFamily GetData(string key1, string key2, params CassandraObject[] columns)
+ public FluentColumnFamily GetData2(string key1, string key2, params CassandraObject[] columns)
{
var productFamily = _db.GetColumnFamily("Data");
var key = new CompositeType<AsciiType, AsciiType>(key1, key2);
return productFamily.Get(key).FetchColumns(columns).FirstOrDefault();
}
+
+ [Fact]
+ public void Test_Composite3()
+ {
+ // arrange
+ var keyspace = _db.Keyspace;
+
+ // create column family using API
+ _db.TryDropColumnFamily("Data");
+ keyspace.TryCreateColumnFamily(new CassandraColumnFamilySchema {
+ FamilyName = "Data",
+ KeyValueType = CassandraType.CompositeType(CassandraType.AsciiType, CassandraType.AsciiType, CassandraType.TimeUUIDType),
+ ColumnNameType = CassandraType.AsciiType,
+ DefaultColumnValueType = CassandraType.BytesType
+ });
+
+ var stamp = new DateTimeOffset(2012, 6, 22, 4, 41, 00, TimeSpan.Zero);
+
+ InsertData3("TT", "A", stamp, new Dictionary<string, string> { { "Status", "Working" } });
+
+ // act
+ var actual = GetData3("TT", "A", stamp, "Status");
+
+ // assert
+ Assert.NotNull(actual);
+ Assert.Equal(1, actual.Columns.Count);
+ }
+
+ public void InsertData3(string key1, string key2, DateTimeOffset stamp, Dictionary<string, string> values)
+ {
+ var productFamily = _db.GetColumnFamily("Data");
+ var key = new CompositeType<AsciiType, AsciiType, TimeUUIDType>(key1, key2, stamp);
+
+ var post = productFamily.CreateRecord(key);
+ _db.Attach(post);
+
+ foreach (var fieldValue in values)
+ post.TrySetColumn(fieldValue.Key, fieldValue.Value);
+
+ _db.SaveChanges();
+ }
+
+ public FluentColumnFamily GetData3(string key1, string key2, DateTimeOffset stamp, params CassandraObject[] columns)
+ {
+ var productFamily = _db.GetColumnFamily("Data");
+ var key = new CompositeType<AsciiType, AsciiType, TimeUUIDType>(key1, key2, stamp);
+
+ return productFamily.Get(key).FetchColumns(columns).FirstOrDefault();
+ }
}
}
Please sign in to comment.
Something went wrong with that request. Please try again.