Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge remote-tracking branch 'upstream/master'

  • Loading branch information...
commit a6e2327b50175567a7ec7e62c5f9dca27ce29581 2 parents 308d1db + 689c346
Grant Pexsa authored
View
2  src/CassandraColumnFamilyOperations.cs
@@ -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, TimestampHelper.UtcNow(), null);
}
public static void InsertColumn(this CassandraColumnFamily family, CassandraObject key, CassandraObject columnName, BytesType columnValue, DateTimeOffset timestamp, int? timeToLive)
View
2  src/CassandraSuperColumnFamilyOperations.cs
@@ -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, TimestampHelper.UtcNow(), null);
}
public static void InsertColumn(this CassandraSuperColumnFamily family, CassandraObject key, CassandraObject superColumnName, CassandraObject name, BytesType value, DateTimeOffset timestamp, int? timeToLive)
View
6 src/Connections/ConnectionBuilder.cs
@@ -82,7 +82,7 @@ private void InitializeConnectionString(string connectionString)
if (nameValue.Length != 2)
continue;
- pairs.Add(nameValue[0], nameValue[1]);
+ pairs.Add(nameValue[0].Trim(), nameValue[1].Trim());
}
#region Keyspace
@@ -330,12 +330,12 @@ private void InitializeConnectionString(string connectionString)
foreach (var server in servers)
{
string[] serverParts = server.Split(':');
- string host = serverParts[0];
+ string host = serverParts[0].Trim();
if (serverParts.Length == 2)
{
int port;
- if (Int32.TryParse(serverParts[1], out port))
+ if (Int32.TryParse(serverParts[1].Trim(), out port))
Servers.Add(new Server(host: host, port: port, timeout: ConnectionTimeout.Seconds));
else
Servers.Add(new Server(host: host, timeout: ConnectionTimeout.Seconds));
View
2  src/FluentCassandra.csproj
@@ -127,6 +127,7 @@
<Compile Include="CassandraCqlRowSchema.cs" />
<Compile Include="CqlHelper.cs" />
<Compile Include="FluentCqlRow.cs" />
+ <Compile Include="GuidGeneration.cs" />
<Compile Include="ILoadable.cs" />
<Compile Include="FluentCassandraException.cs" />
<Compile Include="FluentColumn.cs">
@@ -217,6 +218,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
2  src/FluentCassandra.nuspec
@@ -2,7 +2,7 @@
<package>
<metadata>
<id>FluentCassandra</id>
- <version>1.1.6</version>
+ <version>1.1.7</version>
<title>Fluent Cassandra</title>
<authors>Nick Berardi</authors>
<owners>Managed Fusion, LLC</owners>
View
6 src/FluentColumn.cs
@@ -32,7 +32,7 @@ public FluentColumn(CassandraColumnSchema schema = null)
{
SetSchema(schema);
- ColumnTimestamp = DateTimeOffset.UtcNow;
+ ColumnTimestamp = TimestampHelper.UtcNow();
ColumnSecondsUntilDeleted = null;
ColumnTimeUntilDeleted = null;
}
@@ -46,7 +46,7 @@ public CassandraObject ColumnName
set
{
_name = value.GetValue(GetSchema().NameType);
- ColumnTimestamp = DateTimeOffset.UtcNow;
+ ColumnTimestamp = TimestampHelper.UtcNow();
}
}
@@ -59,7 +59,7 @@ public CassandraObject ColumnValue
set
{
_value = value.GetValue(GetSchema().ValueType);
- ColumnTimestamp = DateTimeOffset.UtcNow;
+ ColumnTimestamp = TimestampHelper.UtcNow();
}
}
View
40 src/FluentColumnFamily.cs
@@ -80,18 +80,8 @@ public CassandraObject Key
/// <returns></returns>
public CassandraObject this[CassandraObject columnName]
{
- get
- {
- object value;
- if (!TryGetColumn(columnName, out value))
- throw new CassandraException(String.Format("Column, {0}, could not be found.", columnName));
-
- return (CassandraObject)value;
- }
- set
- {
- TrySetColumn(columnName, value);
- }
+ get { return GetColumnValue(columnName); }
+ set { SetColumn(columnName, value); }
}
/// <summary>
@@ -146,7 +136,7 @@ public override IList<FluentColumn> Columns
get { return _columns; }
}
- /// <summary>
+ /// <summary>
/// Gets the path.
/// </summary>
/// <returns></returns>
@@ -249,9 +239,31 @@ public override bool TrySetColumn(object name, object value)
return true;
}
+ public override bool TryRemoveColumn(object name)
+ {
+ var col = Columns.FirstOrDefault(c => c.ColumnName == name);
+
+ if (col != null) {
+ Columns.Remove(col);
+ return true;
+ }
+
+ var schema = GetColumnSchema(name);
+ var mutationType = MutationType.Removed;
+
+ col = new FluentColumn(schema);
+ col.ColumnName = CassandraObject.GetCassandraObjectFromObject(name, schema.NameType);
+ col.SetParent(GetSelf());
+
+ // notify the tracker that the column has changed
+ OnColumnMutated(mutationType, col);
+
+ return true;
+ }
+
public override string ToString()
{
return String.Format("{0} - {1}", FamilyName, Key);
}
}
-}
+}
View
7 src/FluentCqlRow.cs
@@ -95,6 +95,11 @@ public override bool TrySetColumn(object name, object value)
throw new NotSupportedException();
}
+ public override bool TryRemoveColumn(object name)
+ {
+ throw new NotSupportedException();
+ }
+
public string FamilyName
{
get;
@@ -112,7 +117,7 @@ public override IList<FluentColumn> Columns
get { return _columns; }
}
- public CassandraObject this[CassandraObject columnName]
+ public CassandraObject this[CassandraObject columnName]
{
get
{
View
2  src/FluentMutation.cs
@@ -9,7 +9,7 @@ public class FluentMutation
/// </summary>
internal FluentMutation()
{
- ColumnTimestamp = DateTimeOffset.UtcNow;
+ ColumnTimestamp = TimestampHelper.UtcNow();
}
/// <summary>
View
85 src/FluentRecord.cs
@@ -9,7 +9,7 @@ namespace FluentCassandra
/// <summary>
///
/// </summary>
- /// <typeparam name="T">A type that impliments <see cref="IFluentColumn"/>.</typeparam>
+ /// <typeparam name="T">A type that implements <see cref="IFluentColumn"/>.</typeparam>
public abstract class FluentRecord<T> : DynamicObject, IFluentRecord, INotifyPropertyChanged, IEnumerable<IFluentBaseColumn>, ILoadable
where T : IFluentBaseColumn
{
@@ -27,6 +27,53 @@ public FluentRecord()
/// </summary>
public abstract IList<T> Columns { get; }
+ public T GetColumn(object name)
+ {
+ var col = Columns.FirstOrDefault(c => c.ColumnName == name);
+
+ if (col == null)
+ return default(T);
+
+ return col;
+ }
+
+ public bool SetColumn(object name, object value)
+ {
+ return TrySetColumn(name, value);
+ }
+
+ public bool RemoveColumn(object name)
+ {
+ return TryRemoveColumn(name);
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="name"></param>
+ /// <param name="result"></param>
+ /// <returns></returns>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public abstract bool TryGetColumn(object name, out object result);
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="name"></param>
+ /// <param name="value"></param>
+ /// <returns></returns>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public abstract bool TrySetColumn(object name, object value);
+
+
+ ///
+ /// </summary>
+ /// <param name="name"></param>
+ /// <param name="value"></param>
+ /// <returns></returns>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public abstract bool TryRemoveColumn(object name);
+
/// <summary>
///
/// </summary>
@@ -66,15 +113,6 @@ public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out ob
/// <summary>
///
/// </summary>
- /// <param name="name"></param>
- /// <param name="result"></param>
- /// <returns></returns>
- [EditorBrowsable(EditorBrowsableState.Never)]
- public abstract bool TryGetColumn(object name, out object result);
-
- /// <summary>
- ///
- /// </summary>
/// <param name="binder"></param>
/// <param name="value"></param>
/// <returns></returns>
@@ -105,7 +143,24 @@ public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object
/// <param name="value"></param>
/// <returns></returns>
[EditorBrowsable(EditorBrowsableState.Never)]
- public abstract bool TrySetColumn(object name, object value);
+ public override bool TryDeleteMember(DeleteMemberBinder binder)
+ {
+ return TryRemoveColumn(binder.Name);
+ }
+
+ /// <summary>
+ ///
+ /// </summary>
+ /// <param name="binder"></param>
+ /// <param name="indexes"></param>
+ /// <param name="value"></param>
+ /// <returns></returns>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override bool TryDeleteIndex(DeleteIndexBinder binder, object[] indexes)
+ {
+ object index0 = indexes[0];
+ return TryRemoveColumn(index0);
+ }
protected bool SuppressMutationTracking { get; private set; }
@@ -170,14 +225,6 @@ public IFluentMutationTracker MutationTracker
private set;
}
- public void RemoveColumn(object name)
- {
- var col = Columns.FirstOrDefault(c => c.ColumnName == name);
-
- if (col != null)
- Columns.Remove(col);
- }
-
#endregion
}
}
View
27 src/FluentSuperColumn.cs
@@ -87,7 +87,7 @@ public override IList<FluentColumn> Columns
get { return _columns; }
}
- /// <summary>
+ /// <summary>
///
/// </summary>
public FluentSuperColumnFamily Family
@@ -226,7 +226,7 @@ public override bool TrySetColumn(object name, object value)
var col = Columns.FirstOrDefault(c => c.ColumnName == name);
var mutationType = MutationType.Changed;
- // if column doesn't exisit create it and add it to the columns
+ // if column doesn't exist create it and add it to the columns
if (col == null)
{
var schema = GetColumnSchema(name);
@@ -249,6 +249,29 @@ public override bool TrySetColumn(object name, object value)
return true;
}
+ public override bool TryRemoveColumn(object name)
+ {
+ var col = Columns.FirstOrDefault(c => c.ColumnName == name);
+
+ if (col != null)
+ {
+ Columns.Remove(col);
+ return true;
+ }
+
+ var schema = GetColumnSchema(name);
+ var mutationType = MutationType.Removed;
+
+ col = new FluentColumn(schema);
+ col.ColumnName = CassandraObject.GetCassandraObjectFromObject(name, schema.NameType);
+ col.SetParent(GetPath());
+
+ // notify the tracker that the column has changed
+ OnColumnMutated(mutationType, col);
+
+ return true;
+ }
+
public void SetParent(FluentColumnParent parent)
{
UpdateParent(parent);
View
25 src/FluentSuperColumnFamily.cs
@@ -130,7 +130,7 @@ public override IList<FluentSuperColumn> Columns
get { return _columns; }
}
- /// <summary>
+ /// <summary>
///
/// </summary>
public CassandraColumnFamilySchema GetSchema()
@@ -251,6 +251,29 @@ public override bool TrySetColumn(object name, object value)
return true;
}
+ public override bool TryRemoveColumn(object name)
+ {
+ var col = Columns.FirstOrDefault(c => c.ColumnName == name);
+
+ if (col != null)
+ {
+ Columns.Remove(col);
+ return true;
+ }
+
+ var schema = GetColumnSchema(name);
+ var mutationType = MutationType.Removed;
+
+ col = new FluentSuperColumn(schema);
+ col.ColumnName = CassandraObject.GetCassandraObjectFromObject(name, schema.NameType);
+ col.SetParent(GetSelf());
+
+ // notify the tracker that the column has changed
+ OnColumnMutated(mutationType, col);
+
+ return true;
+ }
+
public override string ToString()
{
return String.Format("{0} - {1}", FamilyName, Key);
View
10 src/GuidGeneration.cs
@@ -0,0 +1,10 @@
+using System;
+
+namespace FluentCassandra
+{
+ public enum GuidGeneration
+ {
+ Fast,
+ NoDuplicates
+ }
+}
View
142 src/GuidGenerator.cs
@@ -1,5 +1,6 @@
using System;
-using System.Diagnostics;
+using System.Net;
+using System.Net.NetworkInformation;
namespace FluentCassandra
{
@@ -7,20 +8,25 @@ namespace FluentCassandra
/// 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;
+ private static readonly Random Random;
+ private static readonly object Lock = new object();
+
+ private static DateTimeOffset _lastTimestampForNoDuplicatesGeneration = TimestampHelper.UtcNow();
+
+ // number of bytes in uuid
+ private const int ByteArraySize = 16;
// multiplex variant info
- public const int VariantByte = 8;
- public const int VariantByteMask = 0x3f;
- public const int VariantByteShift = 0x80;
+ private const int VariantByte = 8;
+ private const int VariantByteMask = 0x3f;
+ private const int VariantByteShift = 0x80;
// multiplex version info
- public const int VersionByte = 7;
- public const int VersionByteMask = 0x0f;
- public const int VersionByteShift = 4;
+ private const int VersionByte = 7;
+ private const int VersionByteMask = 0x0f;
+ private const int VersionByteShift = 4;
// indexes within the uuid array for certain boundaries
private const byte TimestampByte = 0;
@@ -30,21 +36,75 @@ 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 clock sequence and node
- public static byte[] DefaultClockSequence { get; set; }
- public static byte[] DefaultNode { get; set; }
+ public static GuidGeneration GuidGeneration { get; set; }
+
+ public static byte[] NodeBytes { get; set; }
+ public static byte[] ClockSequenceBytes { get; set; }
static GuidGenerator()
{
- DefaultClockSequence = new byte[2];
- DefaultNode = new byte[6];
+ Random = new Random();
+
+ GuidGeneration = GuidGeneration.NoDuplicates;
+ NodeBytes = GenerateNodeBytes();
+ ClockSequenceBytes = GenerateClockSequenceBytes();
+ }
+
+ /// <summary>
+ /// Generates a random value for the node.
+ /// </summary>
+ /// <returns></returns>
+ public static byte[] GenerateNodeBytes()
+ {
+ var node = new byte[6];
- var random = new Random();
- random.NextBytes(DefaultClockSequence);
- random.NextBytes(DefaultNode);
+ Random.NextBytes(node);
+ return node;
}
- public static GuidVersion GetVersion(this Guid guid)
+ /// <summary>
+ /// Generates a node based on the first 6 bytes of an IP address.
+ /// </summary>
+ /// <param name="ip"></param>
+ public static byte[] GenerateNodeBytes(IPAddress ip)
+ {
+ if (ip == null)
+ throw new ArgumentNullException("ip");
+
+ var bytes = ip.GetAddressBytes();
+
+ if (bytes.Length < 6)
+ throw new ArgumentOutOfRangeException("ip", "The passed in IP address must contain at least 6 bytes.");
+
+ var node = new byte[6];
+ Array.Copy(bytes, node, 6);
+
+ return node;
+ }
+
+ /// <summary>
+ /// Generates a node based on the bytes of the MAC address.
+ /// </summary>
+ /// <param name="mac"></param>
+ /// <remarks>The machines MAC address can be retrieved from <see cref="NetworkInterface.GetPhysicalAddress"/>.</remarks>
+ public static byte[] GenerateNodeBytes(PhysicalAddress mac)
+ {
+ if (mac == null)
+ throw new ArgumentNullException("mac");
+
+ var node = mac.GetAddressBytes();
+
+ return node;
+ }
+
+ public static byte[] GenerateClockSequenceBytes()
+ {
+ var bytes = new byte[2];
+ Random.NextBytes(bytes);
+ return bytes;
+ }
+
+ public static GuidVersion GetUuidVersion(this Guid guid)
{
byte[] bytes = guid.ToByteArray();
return (GuidVersion)((bytes[VersionByte] & 0xFF) >> VersionByteShift);
@@ -84,17 +144,55 @@ public static DateTime GetUtcDateTime(Guid guid)
public static Guid GenerateTimeBasedGuid()
{
- return GenerateTimeBasedGuid(DateTimeOffset.UtcNow, DefaultClockSequence, DefaultNode);
+ switch(GuidGeneration)
+ {
+ case GuidGeneration.Fast:
+ return GenerateTimeBasedGuid(TimestampHelper.UtcNow(), ClockSequenceBytes, NodeBytes);
+
+ case GuidGeneration.NoDuplicates:
+ default:
+ lock (Lock)
+ {
+ var ts = TimestampHelper.UtcNow();
+
+ if (ts <= _lastTimestampForNoDuplicatesGeneration)
+ ClockSequenceBytes = GenerateClockSequenceBytes();
+
+ _lastTimestampForNoDuplicatesGeneration = ts;
+
+ return GenerateTimeBasedGuid(ts, ClockSequenceBytes, NodeBytes);
+ }
+ }
}
public static Guid GenerateTimeBasedGuid(DateTime dateTime)
{
- return GenerateTimeBasedGuid(dateTime, DefaultClockSequence, DefaultNode);
+ return GenerateTimeBasedGuid(dateTime, GenerateClockSequenceBytes(), NodeBytes);
}
public static Guid GenerateTimeBasedGuid(DateTimeOffset dateTime)
{
- return GenerateTimeBasedGuid(dateTime, DefaultClockSequence, DefaultNode);
+ return GenerateTimeBasedGuid(dateTime, GenerateClockSequenceBytes(), NodeBytes);
+ }
+
+ public static Guid GenerateTimeBasedGuid(DateTime dateTime, PhysicalAddress mac)
+ {
+ return GenerateTimeBasedGuid(dateTime, GenerateClockSequenceBytes(), GenerateNodeBytes(mac));
+ }
+
+ public static Guid GenerateTimeBasedGuid(DateTimeOffset dateTime, PhysicalAddress mac)
+ {
+ return GenerateTimeBasedGuid(dateTime, GenerateClockSequenceBytes(), GenerateNodeBytes(mac));
+ }
+
+ public static Guid GenerateTimeBasedGuid(DateTime dateTime, IPAddress ip)
+ {
+ return GenerateTimeBasedGuid(dateTime, GenerateClockSequenceBytes(), GenerateNodeBytes(ip));
+ }
+
+ public static Guid GenerateTimeBasedGuid(DateTimeOffset dateTime, IPAddress ip)
+ {
+ return GenerateTimeBasedGuid(dateTime, GenerateClockSequenceBytes(), GenerateNodeBytes(ip));
}
public static Guid GenerateTimeBasedGuid(DateTime dateTime, byte[] clockSequence, byte[] node)
View
7 src/Operations/Remove.cs
@@ -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(),
+ TimestampHelper.UtcNow().ToCassandraTimestamp(),
Session.WriteConsistency
);
View
88 src/System/DateTimePrecise.cs
@@ -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;
+ }
+ }
+}
View
19 src/System/Numerics/BigDecimal.cs
@@ -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
25 src/TimestampHelper.cs
@@ -1,7 +1,5 @@
using System;
-using System.Collections.Generic;
using System.Linq;
-using System.Text;
namespace FluentCassandra
{
@@ -12,30 +10,43 @@ 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);
}
+ /// <summary>
+ /// Allows for the use of alternative timestamp providers.
+ /// </summary>
+ public static Func<DateTimeOffset> UtcNow = () => DateTimePrecise.UtcNowOffset;
+
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);
}
View
13 src/Types/CassandraObject.cs
@@ -207,16 +207,13 @@ public static CassandraObject GetCassandraObjectFromDatabaseByteArray(byte[] val
return GetCassandraObjectFromDatabaseByteArray(value, cassandraType);
}
- public static CassandraObject GetCassandraObjectFromObject(object obj)
+ public static CassandraObject GetCassandraObjectFromObject(object obj, CassandraType cassandraType = null)
{
- var sourceType = obj.GetType();
- var cassandraType = CassandraType.GetCassandraType(sourceType);
+ if (cassandraType == null) {
+ var sourceType = obj.GetType();
+ cassandraType = CassandraType.GetCassandraType(sourceType);
+ }
- return GetCassandraObjectFromObject(obj, cassandraType);
- }
-
- public static CassandraObject GetCassandraObjectFromObject(object obj, CassandraType cassandraType)
- {
if (obj == null)
return null;
View
130 test/FluentCassandra.Tests/Connections/ConnectionBuilderTests.cs
@@ -0,0 +1,130 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Xunit;
+using System.Configuration;
+
+namespace FluentCassandra.Connections
+{
+ public class ConnectionBuilderTests
+ {
+ [Fact]
+ public void SpacesBeforeServerHostnamesTest()
+ {
+ // arrange
+ IList<Server> expected = new List<Server>();
+ expected.Add(new Server("test-host-1"));
+ expected.Add(new Server("test-host-2"));
+ expected.Add(new Server("test-host-3"));
+ string connectionString = string.Format("Keyspace={0};Server={1}, {2}, {3};Pooling=True", ConfigurationManager.AppSettings["TestKeySpace"], expected[0].Host, expected[1].Host, expected[2].Host);
+ // act
+ IList<Server> actual = new ConnectionBuilder(connectionString).Servers;
+
+ // assert
+ Assert.Equal(expected.Count, actual.Count);
+ for (int i = 0; i < expected.Count; i++)
+ {
+ Server e = expected[i];
+ Server a = actual[i];
+ Assert.Equal(e.Host, a.Host);
+ }
+ }
+
+ [Fact]
+ public void SpacesAfterServerHostnamesTest()
+ {
+ // arrange
+ IList<Server> expected = new List<Server>();
+ expected.Add(new Server("test-host-1"));
+ expected.Add(new Server("test-host-2"));
+ expected.Add(new Server("test-host-3"));
+ string connectionString = string.Format("Keyspace={0};Server={1} ,{2} ,{3};Pooling=True", ConfigurationManager.AppSettings["TestKeySpace"], expected[0].Host, expected[1].Host, expected[2].Host);
+ // act
+ IList<Server> actual = new ConnectionBuilder(connectionString).Servers;
+
+ // assert
+ Assert.Equal(expected.Count, actual.Count);
+ for (int i = 0; i < expected.Count; i++)
+ {
+ Server e = expected[i];
+ Server a = actual[i];
+ Assert.Equal(e.Host, a.Host);
+ }
+ }
+
+ [Fact]
+ public void NormalServerHostnamesTest()
+ {
+ // arrange
+ IList<Server> expected = new List<Server>();
+ expected.Add(new Server("test-host-1"));
+ expected.Add(new Server("test-host-2"));
+ expected.Add(new Server("test-host-3"));
+ string connectionString = string.Format("Keyspace={0};Server={1},{2},{3};Pooling=True", ConfigurationManager.AppSettings["TestKeySpace"], expected[0].Host, expected[1].Host, expected[2].Host);
+ // act
+ IList<Server> actual = new ConnectionBuilder(connectionString).Servers;
+
+ // assert
+ Assert.Equal(expected.Count, actual.Count);
+ for (int i = 0; i < expected.Count; i++)
+ {
+ Server e = expected[i];
+ Server a = actual[i];
+ Assert.Equal(e.Host, a.Host);
+ }
+ }
+
+ [Fact]
+ public void LeadingAndTralingSpacesOnKeyTest()
+ {
+ // arrange
+ string expectedKeyspace = ConfigurationManager.AppSettings["TestKeySpace"];
+ IList<Server> expected = new List<Server>();
+ expected.Add(new Server("test-host-1"));
+ expected.Add(new Server("test-host-2"));
+ expected.Add(new Server("test-host-3"));
+ string connectionString = string.Format(" Keyspace ={0}; Server ={1},{2},{3}; Pooling =True", ConfigurationManager.AppSettings["TestKeySpace"], expected[0].Host, expected[1].Host, expected[2].Host);
+ // act
+ ConnectionBuilder result = new ConnectionBuilder(connectionString);
+ IList<Server> actual = result.Servers;
+ string actualKeyspace = result.Keyspace;
+ // assert
+ Assert.True(result.Pooling);
+ Assert.Equal(expectedKeyspace, actualKeyspace);
+ Assert.Equal(expected.Count, actual.Count);
+ for (int i = 0; i < expected.Count; i++)
+ {
+ Server e = expected[i];
+ Server a = actual[i];
+ Assert.Equal(e.Host, a.Host);
+ }
+ }
+
+ [Fact]
+ public void LeadingAndTralingSpacesOnValueTest()
+ {
+ // arrange
+ string expectedKeyspace = ConfigurationManager.AppSettings["TestKeySpace"];
+ IList<Server> expected = new List<Server>();
+ expected.Add(new Server("test-host-1"));
+ expected.Add(new Server("test-host-2"));
+ expected.Add(new Server("test-host-3"));
+ string connectionString = string.Format("Keyspace= {0} ;Server= {1},{2},{3} ;Pooling= True ", ConfigurationManager.AppSettings["TestKeySpace"], expected[0].Host, expected[1].Host, expected[2].Host);
+ // act
+ ConnectionBuilder result = new ConnectionBuilder(connectionString);
+ IList<Server> actual = result.Servers;
+ string actualKeyspace = result.Keyspace;
+ // assert
+ Assert.True(result.Pooling);
+ Assert.Equal(expectedKeyspace, actualKeyspace);
+ Assert.Equal(expected.Count, actual.Count);
+ for (int i = 0; i < expected.Count; i++)
+ {
+ Server e = expected[i];
+ Server a = actual[i];
+ Assert.Equal(e.Host, a.Host);
+ }
+ }
+ }
+}
View
1  test/FluentCassandra.Tests/FluentCassandra.Tests.csproj
@@ -59,6 +59,7 @@
<Compile Include="Bugs\Issue65ServerTimeoutLost.cs" />
<Compile Include="CassandraDatabaseSetupFixture.cs" />
<Compile Include="CassandraQueryTest.cs" />
+ <Compile Include="Connections\ConnectionBuilderTests.cs" />
<Compile Include="Connections\ConnectionProviderTests.cs" />
<Compile Include="Connections\NormalConnectionProviderTests.cs" />
<Compile Include="CqlHelperTest.cs" />
View
46 test/FluentCassandra.Tests/GuidGeneratorTest.cs
@@ -4,7 +4,6 @@
namespace FluentCassandra
{
-
public class GuidGeneratorTest
{
[Fact]
@@ -15,7 +14,7 @@ public void Type1Check()
var guid = GuidGenerator.GenerateTimeBasedGuid();
// act
- var actual = guid.GetVersion();
+ var actual = guid.GetUuidVersion();
// assert
Assert.Equal(expected, actual);
@@ -29,7 +28,7 @@ public void SanityType1Check()
var guid = Guid.NewGuid();
// act
- var actual = guid.GetVersion();
+ var actual = guid.GetUuidVersion();
// assert
Assert.NotEqual(expected, actual);
@@ -90,5 +89,46 @@ public void GetDateTimeOffset()
// assert
Assert.Equal(expected, actual);
}
+
+ [Fact]
+ public void DoesNotCreateDuplicateWhenTimeHasNotPassed()
+ {
+ // arrange
+ DateTimeOffset currentTime = DateTimeOffset.UtcNow;
+
+ TimestampHelper.UtcNow = () => currentTime; //make sure all calls will return the same time
+ Guid firstGuid = GuidGenerator.GenerateTimeBasedGuid();
+
+ // act
+ Guid secondGuid = GuidGenerator.GenerateTimeBasedGuid();
+
+ // assert
+ Assert.True(firstGuid != secondGuid, "first: " + firstGuid + " second: " + secondGuid);
+ //Assert.NotEqual(firstGuid,secondGuid);
+ }
+
+ [Fact]
+ public void ClockSequenceChangesWhenTimeMovesBackward()
+ {
+ Func<Guid, short> getClockSequence = (guid) => {
+ byte[] clockSequenceBytes = new byte[2];
+ Array.Copy(guid.ToByteArray(), 8, clockSequenceBytes, 0, 2);
+ return BitConverter.ToInt16(clockSequenceBytes, 0);
+ };
+
+ // arrange
+ DateTimeOffset currentTime = DateTimeOffset.UtcNow;
+
+ TimestampHelper.UtcNow = () => currentTime;
+ Guid firstGuid = GuidGenerator.GenerateTimeBasedGuid();
+
+ // act
+ TimestampHelper.UtcNow = () => currentTime.AddTicks(-1); //make sure clock went backwards
+ Guid secondGuid = GuidGenerator.GenerateTimeBasedGuid();
+
+ // assert
+ //clock sequence is not equal
+ Assert.NotEqual(getClockSequence(firstGuid), getClockSequence(secondGuid));
+ }
}
}
Please sign in to comment.
Something went wrong with that request. Please try again.