Permalink
Browse files

checking in changes for clock sequence logic, and merged changes?

  • Loading branch information...
2 parents 530e73e + e8ccbe9 commit 2c5b5a4b97ced04455ec496e476718e348cad209 Grant Pexsa committed Sep 24, 2012
@@ -43,7 +43,7 @@ public static void InsertColumn(this CassandraColumnFamily family, CassandraObje
public static void InsertColumn(this CassandraColumnFamily family, CassandraObject key, CassandraObject columnName, BytesType columnValue)
{
- InsertColumn(family, key, columnName, columnValue, DateTimeOffset.UtcNow, null);
+ InsertColumn(family, key, columnName, columnValue, DateTimePrecise.UtcNowOffset, null);
}
public static void InsertColumn(this CassandraColumnFamily family, CassandraObject key, CassandraObject columnName, BytesType columnValue, DateTimeOffset timestamp, int? timeToLive)
@@ -56,7 +56,7 @@ public static void InsertColumn(this CassandraSuperColumnFamily family, Cassandr
public static void InsertColumn(this CassandraSuperColumnFamily family, CassandraObject key, CassandraObject superColumnName, CassandraObject name, BytesType value)
{
- InsertColumn(family, key, superColumnName, name, value, DateTimeOffset.UtcNow, null);
+ InsertColumn(family, key, superColumnName, name, value, DateTimePrecise.UtcNowOffset, null);
}
public static void InsertColumn(this CassandraSuperColumnFamily family, CassandraObject key, CassandraObject superColumnName, CassandraObject name, BytesType value, DateTimeOffset timestamp, int? timeToLive)
@@ -217,6 +217,7 @@
<Compile Include="Operations\Void.cs">
<SubType>Code</SubType>
</Compile>
+ <Compile Include="System\DateTimePrecise.cs" />
<Compile Include="Thrift\Collections\THashSet.cs" />
<Compile Include="Thrift\Protocol\TBase.cs" />
<Compile Include="Thrift\Protocol\TBase64Utils.cs" />
View
@@ -32,7 +32,7 @@ public FluentColumn(CassandraColumnSchema schema = null)
{
SetSchema(schema);
- ColumnTimestamp = DateTimeOffset.UtcNow;
+ ColumnTimestamp = DateTimePrecise.UtcNowOffset;
ColumnSecondsUntilDeleted = null;
ColumnTimeUntilDeleted = null;
}
@@ -46,7 +46,7 @@ public CassandraObject ColumnName
set
{
_name = value.GetValue(GetSchema().NameType);
- ColumnTimestamp = DateTimeOffset.UtcNow;
+ ColumnTimestamp = DateTimePrecise.UtcNowOffset;
}
}
@@ -59,7 +59,7 @@ public CassandraObject ColumnValue
set
{
_value = value.GetValue(GetSchema().ValueType);
- ColumnTimestamp = DateTimeOffset.UtcNow;
+ ColumnTimestamp = DateTimePrecise.UtcNowOffset;
}
}
View
@@ -9,7 +9,7 @@ public class FluentMutation
/// </summary>
internal FluentMutation()
{
- ColumnTimestamp = DateTimeOffset.UtcNow;
+ ColumnTimestamp = DateTimePrecise.UtcNowOffset;
}
/// <summary>
View
@@ -1,13 +1,13 @@
using System;
-using System.Threading;
+using System.Diagnostics;
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
+ public static class GuidGenerator
{
// number of bytes in guid
public const int ByteArraySize = 16;
@@ -30,23 +30,22 @@ 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 DateTimeOffset GregorianCalendarStart = new DateTimeOffset(1582, 10, 15, 0, 0, 0, TimeSpan.Zero);
- private static long ticksFromLastGuid = TimeUUIDHelper.UtcNow().Ticks;
- private static long clockSequenceForLastGuid;
- private static object Semaphore = new object();
- private static Random random = new Random();
- private static short nextSequence;
+ private static long TicksFromLastGuid = TimeUUIDHelper.UtcNow().Ticks;
+ private static object Semaphore = new object();
+
+ public static byte[] CurrentSequence = new byte[2];
+
+ private static readonly Random random = new Random();
+
- // random clock sequence and node
- public static byte[] ClockSequence { get; set; }
public static byte[] DefaultNode { get; set; }
static GuidGenerator()
{
- ClockSequence = new byte[2];
DefaultNode = new byte[6];
- random.NextBytes(ClockSequence);
- random.NextBytes(DefaultNode);
+ random.NextBytes(DefaultNode);
+ random.NextBytes(CurrentSequence);
}
public static GuidVersion GetVersion(this Guid guid)
@@ -55,6 +54,11 @@ public static GuidVersion GetVersion(this Guid guid)
return (GuidVersion)((bytes[VersionByte] & 0xFF) >> VersionByteShift);
}
+ public static void GenerateNewClockSequence()
+ {
+ random.NextBytes(CurrentSequence);
+ }
+
public static DateTimeOffset GetDateTimeOffset(Guid guid)
{
byte[] bytes = guid.ToByteArray();
@@ -97,35 +101,32 @@ public static int GetClockSequence(Guid guid)
}
public static Guid GenerateTimeBasedGuid()
- {
+ {
lock (Semaphore)
{
- DateTimeOffset dateTime = TimeUUIDHelper.UtcNow();
- long ticksForThisGuid = dateTime.Ticks;
+ DateTimeOffset offset = TimeUUIDHelper.UtcNow();
- if (ticksForThisGuid <= ticksFromLastGuid) //time has stopped or moved backward since last generation
- {
- nextSequence = (short)(BitConverter.ToInt16(ClockSequence, 0) + 1);
+ long ticksForThisGuid = offset.Ticks;
- ClockSequence = BitConverter.GetBytes(nextSequence);
-
- random.NextBytes(ClockSequence); //regenerate the Clock Sequence
+ if (ticksForThisGuid <= TicksFromLastGuid) //time has stopped or moved backward since last generation
+ {
+ GenerateNewClockSequence();
}
- ticksFromLastGuid = ticksForThisGuid;
+ TicksFromLastGuid = ticksForThisGuid;
- return GenerateTimeBasedGuid(new DateTime(ticksForThisGuid), ClockSequence, DefaultNode);
+ return GenerateTimeBasedGuid(offset, CurrentSequence, DefaultNode);
}
}
- public static Guid GenerateTimeBasedGuid(DateTime dateTime)
+ public static Guid GenerateTimeBasedGuid(DateTime dateTime)
{
- return GenerateTimeBasedGuid(dateTime, ClockSequence, DefaultNode);
+ return GenerateTimeBasedGuid(dateTime, CurrentSequence, DefaultNode);
}
public static Guid GenerateTimeBasedGuid(DateTimeOffset dateTime)
{
- return GenerateTimeBasedGuid(dateTime, ClockSequence, DefaultNode);
+ return GenerateTimeBasedGuid(dateTime, CurrentSequence, DefaultNode);
}
public static Guid GenerateTimeBasedGuid(DateTime dateTime, byte[] clockSequence, byte[] node)
View
@@ -1,15 +1,10 @@
using System;
-using Apache.Cassandra;
using FluentCassandra.Types;
namespace FluentCassandra.Operations
{
public class Remove : ColumnFamilyOperation<Void>
{
- /*
- * remove(keyspace, key, column_path, timestamp, consistency_level)
- */
-
public CassandraObject Key { get; private set; }
public CassandraObject SuperColumnName { get; private set; }
@@ -31,7 +26,7 @@ public override Void Execute()
Session.GetClient().remove(
Key,
path,
- DateTimeOffset.UtcNow.ToCassandraTimestamp(),
+ DateTimePrecise.UtcNowOffset.ToCassandraTimestamp(),
Session.WriteConsistency
);
@@ -0,0 +1,88 @@
+using System;
+using System.Diagnostics;
+using System.Linq;
+
+namespace System
+{
+ public class DateTimePrecise
+ {
+ private static readonly DateTimePrecise Instance = new DateTimePrecise();
+
+ public static DateTime Now
+ {
+ get { return Instance.GetUtcNow().LocalDateTime; }
+ }
+
+ public static DateTime UtcNow
+ {
+ get { return Instance.GetUtcNow().UtcDateTime; }
+ }
+
+ public static DateTimeOffset NowOffset
+ {
+ get { return Instance.GetUtcNow().ToLocalTime(); }
+ }
+
+ public static DateTimeOffset UtcNowOffset
+ {
+ get { return Instance.GetUtcNow(); }
+ }
+
+ private const long TicksInOneSecond = 10000000L;
+
+ private readonly double _divergentSeconds;
+ private readonly double _syncSeconds;
+ private readonly Stopwatch _stopwatch;
+ private DateTimeOffset _baseTime;
+
+ public DateTimePrecise(int syncSeconds = 1, int divergentSeconds = 1)
+ {
+ _syncSeconds = syncSeconds;
+ _divergentSeconds = divergentSeconds;
+
+ _stopwatch = new Stopwatch();
+
+ Syncronize();
+ }
+
+ private void Syncronize()
+ {
+ lock (_stopwatch) {
+ _baseTime = DateTimeOffset.UtcNow;
+ _stopwatch.Restart();
+ }
+ }
+
+ public DateTimeOffset GetUtcNow()
+ {
+ var now = DateTimeOffset.UtcNow;
+ var elapsed = _stopwatch.Elapsed;
+
+ if (elapsed.TotalSeconds > _syncSeconds)
+ {
+ Syncronize();
+
+ // account for any time that has passed since the stopwatch was syncronized
+ elapsed = _stopwatch.Elapsed;
+ }
+
+ /**
+ * The Stopwatch has many bugs associated with it, so when we are in doubt of the results
+ * we are going to default to DateTimeOffset.UtcNow
+ * http://stackoverflow.com/questions/1008345
+ **/
+
+ // check for elapsed being less than zero
+ if (elapsed < TimeSpan.Zero)
+ return now;
+
+ var preciseNow = _baseTime + elapsed;
+
+ // make sure the two clocks don't diverge by more than defined seconds
+ if (Math.Abs((preciseNow - now).TotalSeconds) > _divergentSeconds)
+ return now;
+
+ return _baseTime + elapsed;
+ }
+ }
+}
@@ -3,9 +3,6 @@
namespace System.Numerics
{
- /// <summary>
- /// A crude implimentation of the essentials needed from Java's BigDecimal
- /// </summary>
public struct BigDecimal : IConvertible, IFormattable, IComparable, IComparable<BigDecimal>, IEquatable<BigDecimal>
{
public static readonly BigDecimal MinusOne = new BigDecimal(BigInteger.MinusOne, 0);
@@ -106,20 +103,20 @@ private static byte[] FromDecimal(decimal d)
int hi = bits[2];
int flags = bits[3];
- bytes[0] = (byte)lo;
- bytes[1] = (byte)(lo >> 8);
+ bytes[0] = (byte)(lo);
+ bytes[1] = (byte)(lo >> 0x8);
bytes[2] = (byte)(lo >> 0x10);
bytes[3] = (byte)(lo >> 0x18);
- bytes[4] = (byte)mid;
- bytes[5] = (byte)(mid >> 8);
+ bytes[4] = (byte)(mid);
+ bytes[5] = (byte)(mid >> 0x8);
bytes[6] = (byte)(mid >> 0x10);
bytes[7] = (byte)(mid >> 0x18);
- bytes[8] = (byte)hi;
- bytes[9] = (byte)(hi >> 8);
+ bytes[8] = (byte)(hi);
+ bytes[9] = (byte)(hi >> 0x8);
bytes[10] = (byte)(hi >> 0x10);
bytes[11] = (byte)(hi >> 0x18);
- bytes[12] = (byte)flags;
- bytes[13] = (byte)(flags >> 8);
+ bytes[12] = (byte)(flags);
+ bytes[13] = (byte)(flags >> 0x8);
bytes[14] = (byte)(flags >> 0x10);
bytes[15] = (byte)(flags >> 0x18);
View
@@ -7,7 +7,7 @@ public class TimeUUIDHelper
/// <summary>
/// Allows for substitution for Unit Tests
/// </summary>
- public static Func<DateTimeOffset> UtcNow = () => DateTimeOffset.UtcNow;
+ public static Func<DateTimeOffset> UtcNow = () => DateTimePrecise.UtcNowOffset ;
}
}
View
@@ -1,7 +1,5 @@
using System;
-using System.Collections.Generic;
using System.Linq;
-using System.Text;
namespace FluentCassandra
{
@@ -12,30 +10,38 @@ public static class TimestampHelper
public static readonly long MaxUnixMilliseconds;
public static readonly long MaxUnixMicroseconds;
+ public const long TicksInOneMicrosecond = 10L;
+ public const long TicksInOneMillisecond = 10000L;
+ public const long TicksInOneSecond = 10000000L;
+
static TimestampHelper()
{
UnixStart = new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero);
MaxUnixSeconds = Convert.ToInt64((DateTimeOffset.MaxValue - UnixStart).TotalSeconds);
MaxUnixMilliseconds = Convert.ToInt64((DateTimeOffset.MaxValue - UnixStart).TotalMilliseconds);
- MaxUnixMicroseconds = Convert.ToInt64((DateTimeOffset.MaxValue - UnixStart).Ticks / 10L);
+ MaxUnixMicroseconds = Convert.ToInt64((DateTimeOffset.MaxValue - UnixStart).Ticks / TicksInOneMicrosecond);
}
public static long ToCassandraTimestamp(this DateTimeOffset dt)
{
// we are using the microsecond format from 1/1/1970 00:00:00 UTC same as the Cassandra server
- return (dt - UnixStart).Ticks / 10L;
+ return (dt - UnixStart).Ticks / TicksInOneMicrosecond;
}
public static DateTimeOffset FromCassandraTimestamp(long ts)
{
+ // convert a timestamp in seconds to ticks
+ // ** this should never happen, but it is in here for good measure **
if (ts <= MaxUnixSeconds)
- ts *= 1000L;
+ ts *= TicksInOneSecond;
+ // convert a timestamp in milliseconds to ticks
if (ts <= MaxUnixMilliseconds)
- ts *= 1000L;
+ ts *= TicksInOneMillisecond;
+ // convert a timestamp in microseconds to ticks
if (ts <= MaxUnixMicroseconds)
- ts *= 10L;
+ ts *= TicksInOneMicrosecond;
return UnixStart.AddTicks(ts);
}
Oops, something went wrong.

0 comments on commit 2c5b5a4

Please sign in to comment.