Commit baac1bc1 authored by Marc Gravell's avatar Marc Gravell

Merge branch 'master' of github.com:StackExchange/StackExchange.Redis into core-rtm

parents fafb8cac 5688bc11
...@@ -45,8 +45,8 @@ Given the above information, it's recommend to set the minimum configuration val ...@@ -45,8 +45,8 @@ Given the above information, it's recommend to set the minimum configuration val
How to configure this setting: How to configure this setting:
- In ASP.NET, use the ["minIoThreads" configuration setting](https://msdn.microsoft.com/en-us/library/vstudio/7w2sway1(v=vs.100).aspx) under the `<processModel>` configuration element in web.config. You should be able to set this programmatically (see below) from your Application_Start method in global.asax.cs. - In ASP.NET, use the ["minIoThreads" configuration setting](https://msdn.microsoft.com/en-us/library/vstudio/7w2sway1(v=vs.100).aspx) under the `<processModel>` configuration element in machine.config. If you are running inside of Azure WebSites, this setting is not exposed through the configuration options. You should be able to set this programmatically (see below) from your Application_Start method in global.asax.cs.
> **Important Note:** the value specified in this configuration element is a *per-core* setting. For example, if you have a 4 core machine and want your minIOThreads setting to be 200 at runtime, you would use `<processModel minIoThreads="50"/>`. > **Important Note:** the value specified in this configuration element is a *per-core* setting. For example, if you have a 4 core machine and want your minIOThreads setting to be 200 at runtime, you would use `<processModel minIoThreads="50"/>`.
- Outside of ASP.NET, use the [ThreadPool.SetMinThreads(…)](https://msdn.microsoft.com//en-us/library/system.threading.threadpool.setminthreads(v=vs.100).aspx) API. - Outside of ASP.NET, use the [ThreadPool.SetMinThreads(…)](https://msdn.microsoft.com//en-us/library/system.threading.threadpool.setminthreads(v=vs.100).aspx) API.
\ No newline at end of file
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
<dependencies> <dependencies>
<group targetFramework="net40"> <group targetFramework="net40">
<dependency id="Microsoft.Bcl" version="1.1.9"/> <dependency id="Microsoft.Bcl" version="1.1.10"/>
<dependency id="Microsoft.Bcl.Async" version="1.0.168"/> <dependency id="Microsoft.Bcl.Async" version="1.0.168"/>
</group> </group>
<group targetFramework="net45"> <group targetFramework="net45">
......
...@@ -7,6 +7,14 @@ namespace StackExchange.Redis ...@@ -7,6 +7,14 @@ namespace StackExchange.Redis
/// </summary> /// </summary>
public abstract class RedisResult public abstract class RedisResult
{ {
/// <summary>
/// Create a new RedisResult.
/// </summary>
/// <returns></returns>
public static RedisResult Create(RedisValue value)
{
return new SingleRedisResult(value);
}
// internally, this is very similar to RawResult, except it is designed to be usable // internally, this is very similar to RawResult, except it is designed to be usable
// outside of the IO-processing pipeline: the buffers are standalone, etc // outside of the IO-processing pipeline: the buffers are standalone, etc
......
...@@ -185,7 +185,7 @@ public bool Remove(Action<RedisChannel, RedisValue> value) ...@@ -185,7 +185,7 @@ public bool Remove(Action<RedisChannel, RedisValue> value)
public Task SubscribeToServer(ConnectionMultiplexer multiplexer, RedisChannel channel, CommandFlags flags, object asyncState, bool internalCall) public Task SubscribeToServer(ConnectionMultiplexer multiplexer, RedisChannel channel, CommandFlags flags, object asyncState, bool internalCall)
{ {
var cmd = channel.IsPatternBased ? RedisCommand.PSUBSCRIBE : RedisCommand.SUBSCRIBE; var cmd = channel.IsPatternBased ? RedisCommand.PSUBSCRIBE : RedisCommand.SUBSCRIBE;
var selected = multiplexer.SelectServer(-1, cmd, CommandFlags.DemandMaster, default(RedisKey)); var selected = multiplexer.SelectServer(-1, cmd, flags, default(RedisKey));
if (selected == null || Interlocked.CompareExchange(ref owner, selected, null) != null) return null; if (selected == null || Interlocked.CompareExchange(ref owner, selected, null) != null) return null;
......
using System; using System;
#if CORE_CLR #if CORE_CLR
using System.Collections.Generic; using System.Collections.Generic;
using System.Reflection; using System.Reflection;
#endif #endif
using System.Text; using System.Text;
namespace StackExchange.Redis namespace StackExchange.Redis
{ {
/// <summary> /// <summary>
/// Represents values that can be stored in redis /// Represents values that can be stored in redis
/// </summary> /// </summary>
public struct RedisValue : IEquatable<RedisValue>, IComparable<RedisValue>, IComparable, IConvertible public struct RedisValue : IEquatable<RedisValue>, IComparable<RedisValue>, IComparable, IConvertible
{ {
internal static readonly RedisValue[] EmptyArray = new RedisValue[0]; internal static readonly RedisValue[] EmptyArray = new RedisValue[0];
static readonly byte[] EmptyByteArr = new byte[0]; static readonly byte[] EmptyByteArr = new byte[0];
private static readonly byte[] IntegerSentinel = new byte[0]; private static readonly byte[] IntegerSentinel = new byte[0];
private readonly byte[] valueBlob; private readonly byte[] valueBlob;
private readonly long valueInt64; private readonly long valueInt64;
// internal bool IsNullOrDefaultValue { get { return (valueBlob == null && valueInt64 == 0L) || ((object)valueBlob == (object)NullSentinel); } } // internal bool IsNullOrDefaultValue { get { return (valueBlob == null && valueInt64 == 0L) || ((object)valueBlob == (object)NullSentinel); } }
private RedisValue(long valueInt64, byte[] valueBlob) private RedisValue(long valueInt64, byte[] valueBlob)
{ {
this.valueInt64 = valueInt64; this.valueInt64 = valueInt64;
this.valueBlob = valueBlob; this.valueBlob = valueBlob;
} }
/// <summary> /// <summary>
/// Represents the string <c>""</c> /// Represents the string <c>""</c>
/// </summary> /// </summary>
public static RedisValue EmptyString { get; } = new RedisValue(0, EmptyByteArr); public static RedisValue EmptyString { get; } = new RedisValue(0, EmptyByteArr);
/// <summary> /// <summary>
/// A null value /// A null value
/// </summary> /// </summary>
public static RedisValue Null { get; } = new RedisValue(0, null); public static RedisValue Null { get; } = new RedisValue(0, null);
/// <summary> /// <summary>
/// Indicates whether the value is a primitive integer /// Indicates whether the value is a primitive integer
/// </summary> /// </summary>
public bool IsInteger => valueBlob == IntegerSentinel; public bool IsInteger => valueBlob == IntegerSentinel;
/// <summary> /// <summary>
/// Indicates whether the value should be considered a null value /// Indicates whether the value should be considered a null value
/// </summary> /// </summary>
public bool IsNull => valueBlob == null; public bool IsNull => valueBlob == null;
/// <summary> /// <summary>
/// Indicates whether the value is either null or a zero-length value /// Indicates whether the value is either null or a zero-length value
/// </summary> /// </summary>
public bool IsNullOrEmpty => valueBlob == null || (valueBlob.Length == 0 && !(valueBlob == IntegerSentinel)); public bool IsNullOrEmpty => valueBlob == null || (valueBlob.Length == 0 && !(valueBlob == IntegerSentinel));
/// <summary> /// <summary>
/// Indicates whether the value is greater than zero-length /// Indicates whether the value is greater than zero-length
/// </summary> /// </summary>
public bool HasValue => valueBlob != null && valueBlob.Length > 0; public bool HasValue => valueBlob != null && valueBlob.Length > 0;
/// <summary> /// <summary>
/// Indicates whether two RedisValue values are equivalent /// Indicates whether two RedisValue values are equivalent
/// </summary> /// </summary>
public static bool operator !=(RedisValue x, RedisValue y) public static bool operator !=(RedisValue x, RedisValue y)
{ {
return !(x == y); return !(x == y);
} }
/// <summary> /// <summary>
/// Indicates whether two RedisValue values are equivalent /// Indicates whether two RedisValue values are equivalent
/// </summary> /// </summary>
public static bool operator ==(RedisValue x, RedisValue y) public static bool operator ==(RedisValue x, RedisValue y)
{ {
if (x.valueBlob == null) return y.valueBlob == null; if (x.valueBlob == null) return y.valueBlob == null;
if (x.valueBlob == IntegerSentinel) if (x.valueBlob == IntegerSentinel)
{
if (y.valueBlob == IntegerSentinel)
{
return x.valueInt64 == y.valueInt64;
}
else
{
return Equals((byte[])x, (byte[])y);
}
}
else if (y.valueBlob == IntegerSentinel)
{
return Equals((byte[])x, (byte[])y);
}
return Equals(x.valueBlob, y.valueBlob);
}
/// <summary>
/// See Object.Equals()
/// </summary>
public override bool Equals(object obj)
{
if (obj == null) return valueBlob == null;
if (obj is RedisValue)
{
return Equals((RedisValue)obj);
}
if (obj is string)
{
return (string)obj == (string)this;
}
if (obj is byte[])
{
return Equals((byte[])obj, (byte[])this);
}
if (obj is long)
{
return (long)obj == (long)this;
}
if (obj is int)
{
return (int)obj == (int)this;
}
return false;
}
/// <summary>
/// Indicates whether two RedisValue values are equivalent
/// </summary>
public bool Equals(RedisValue other)
{
return this == other;
}
/// <summary>
/// See Object.GetHashCode()
/// </summary>
public override int GetHashCode()
{
if (valueBlob == IntegerSentinel) return valueInt64.GetHashCode();
if (valueBlob == null) return -1;
return GetHashCode(valueBlob);
}
/// <summary>
/// Returns a string representation of the value
/// </summary>
public override string ToString()
{
return (string)this;
}
internal static unsafe bool Equals(byte[] x, byte[] y)
{
if ((object)x == (object)y) return true; // ref equals
if (x == null || y == null) return false;
int len = x.Length;
if (len != y.Length) return false;
int octets = len / 8, spare = len % 8;
fixed (byte* x8 = x, y8 = y)
{
long* x64 = (long*)x8, y64 = (long*)y8;
for (int i = 0; i < octets; i++)
{
if (x64[i] != y64[i]) return false;
}
int offset = len - spare;
while (spare-- != 0)
{
if (x8[offset] != y8[offset++]) return false;
}
}
return true;
}
internal static unsafe int GetHashCode(byte[] value)
{
unchecked
{
if (value == null) return -1;
int len = value.Length;
if (len == 0) return 0;
int octets = len / 8, spare = len % 8;
int acc = 728271210;
fixed (byte* ptr8 = value)
{
long* ptr64 = (long*)ptr8;
for (int i = 0; i < octets; i++)
{
long val = ptr64[i];
int valHash = (((int)val) ^ ((int)(val >> 32)));
acc = (((acc << 5) + acc) ^ valHash);
}
int offset = len - spare;
while (spare-- != 0)
{
acc = (((acc << 5) + acc) ^ ptr8[offset++]);
}
}
return acc;
}
}
internal static bool TryParseInt64(byte[] value, int offset, int count, out long result)
{
result = 0;
if (value == null || count <= 0) return false;
checked
{ {
int max = offset + count; if (y.valueBlob == IntegerSentinel)
if (value[offset] == '-') {
{ return x.valueInt64 == y.valueInt64;
for (int i = offset + 1; i < max; i++) }
{ else
var b = value[i]; {
if (b < '0' || b > '9') return false; return Equals((byte[])x, (byte[])y);
result = (result * 10) - (b - '0'); }
} }
return true; else if (y.valueBlob == IntegerSentinel)
} {
else return Equals((byte[])x, (byte[])y);
{ }
for (int i = offset; i < max; i++)
{ return Equals(x.valueBlob, y.valueBlob);
var b = value[i]; }
if (b < '0' || b > '9') return false;
result = (result * 10) + (b - '0'); /// <summary>
} /// See Object.Equals()
return true; /// </summary>
} public override bool Equals(object obj)
} {
} if (obj == null) return valueBlob == null;
internal void AssertNotNull() if (obj is RedisValue)
{ {
if (IsNull) throw new ArgumentException("A null value is not valid in this context"); return Equals((RedisValue)obj);
} }
if (obj is string)
enum CompareType { {
Null, Int64, Double, Raw return (string)obj == (string)this;
} }
CompareType ResolveType(out long i64, out double r8) if (obj is byte[])
{ {
byte[] blob = valueBlob; return Equals((byte[])obj, (byte[])this);
if (blob == IntegerSentinel) }
{ if (obj is long)
i64 = valueInt64; {
r8 = default(double); return (long)obj == (long)this;
return CompareType.Int64; }
} if (obj is int)
if(blob == null) {
{ return (int)obj == (int)this;
i64 = default(long); }
r8 = default(double); return false;
return CompareType.Null; }
}
if(TryParseInt64(blob, 0, blob.Length, out i64)) /// <summary>
{ /// Indicates whether two RedisValue values are equivalent
r8 = default(double); /// </summary>
return CompareType.Int64; public bool Equals(RedisValue other)
} {
if(TryParseDouble(blob, out r8)) return this == other;
{ }
i64 = default(long);
return CompareType.Double; /// <summary>
} /// See Object.GetHashCode()
i64 = default(long); /// </summary>
r8 = default(double); public override int GetHashCode()
return CompareType.Raw; {
} if (valueBlob == IntegerSentinel) return valueInt64.GetHashCode();
if (valueBlob == null) return -1;
/// <summary> return GetHashCode(valueBlob);
/// Compare against a RedisValue for relative order }
/// </summary>
public int CompareTo(RedisValue other) /// <summary>
{ /// Returns a string representation of the value
try /// </summary>
{ public override string ToString()
long thisInt64, otherInt64; {
double thisDouble, otherDouble; return (string)this;
CompareType thisType = this.ResolveType(out thisInt64, out thisDouble), }
otherType = other.ResolveType(out otherInt64, out otherDouble);
internal static unsafe bool Equals(byte[] x, byte[] y)
if(thisType == CompareType.Null) {
{ if ((object)x == (object)y) return true; // ref equals
return otherType == CompareType.Null ? 0 : -1; if (x == null || y == null) return false;
} int len = x.Length;
if(otherType == CompareType.Null) if (len != y.Length) return false;
{
return 1; int octets = len / 8, spare = len % 8;
} fixed (byte* x8 = x, y8 = y)
{
if(thisType == CompareType.Int64) long* x64 = (long*)x8, y64 = (long*)y8;
{ for (int i = 0; i < octets; i++)
if (otherType == CompareType.Int64) return thisInt64.CompareTo(otherInt64); {
if (otherType == CompareType.Double) return ((double)thisInt64).CompareTo(otherDouble); if (x64[i] != y64[i]) return false;
} }
else if(thisType == CompareType.Double) int offset = len - spare;
{ while (spare-- != 0)
if (otherType == CompareType.Int64) return thisDouble.CompareTo((double)otherInt64); {
if (otherType == CompareType.Double) return thisDouble.CompareTo(otherDouble); if (x8[offset] != y8[offset++]) return false;
}
}
return true;
}
internal static unsafe int GetHashCode(byte[] value)
{
unchecked
{
if (value == null) return -1;
int len = value.Length;
if (len == 0) return 0;
int octets = len / 8, spare = len % 8;
int acc = 728271210;
fixed (byte* ptr8 = value)
{
long* ptr64 = (long*)ptr8;
for (int i = 0; i < octets; i++)
{
long val = ptr64[i];
int valHash = (((int)val) ^ ((int)(val >> 32)));
acc = (((acc << 5) + acc) ^ valHash);
}
int offset = len - spare;
while (spare-- != 0)
{
acc = (((acc << 5) + acc) ^ ptr8[offset++]);
}
}
return acc;
}
}
internal static bool TryParseInt64(byte[] value, int offset, int count, out long result)
{
result = 0;
if (value == null || count <= 0) return false;
checked
{
int max = offset + count;
if (value[offset] == '-')
{
for (int i = offset + 1; i < max; i++)
{
var b = value[i];
if (b < '0' || b > '9') return false;
result = (result * 10) - (b - '0');
}
return true;
}
else
{
for (int i = offset; i < max; i++)
{
var b = value[i];
if (b < '0' || b > '9') return false;
result = (result * 10) + (b - '0');
}
return true;
}
}
}
internal void AssertNotNull()
{
if (IsNull) throw new ArgumentException("A null value is not valid in this context");
}
enum CompareType {
Null, Int64, Double, Raw
}
CompareType ResolveType(out long i64, out double r8)
{
byte[] blob = valueBlob;
if (blob == IntegerSentinel)
{
i64 = valueInt64;
r8 = default(double);
return CompareType.Int64;
}
if(blob == null)
{
i64 = default(long);
r8 = default(double);
return CompareType.Null;
}
if(TryParseInt64(blob, 0, blob.Length, out i64))
{
r8 = default(double);
return CompareType.Int64;
}
if(TryParseDouble(blob, out r8))
{
i64 = default(long);
return CompareType.Double;
}
i64 = default(long);
r8 = default(double);
return CompareType.Raw;
}
/// <summary>
/// Compare against a RedisValue for relative order
/// </summary>
public int CompareTo(RedisValue other)
{
try
{
long thisInt64, otherInt64;
double thisDouble, otherDouble;
CompareType thisType = this.ResolveType(out thisInt64, out thisDouble),
otherType = other.ResolveType(out otherInt64, out otherDouble);
if(thisType == CompareType.Null)
{
return otherType == CompareType.Null ? 0 : -1;
}
if(otherType == CompareType.Null)
{
return 1;
}
if(thisType == CompareType.Int64)
{
if (otherType == CompareType.Int64) return thisInt64.CompareTo(otherInt64);
if (otherType == CompareType.Double) return ((double)thisInt64).CompareTo(otherDouble);
}
else if(thisType == CompareType.Double)
{
if (otherType == CompareType.Int64) return thisDouble.CompareTo((double)otherInt64);
if (otherType == CompareType.Double) return thisDouble.CompareTo(otherDouble);
} }
// otherwise, compare as strings // otherwise, compare as strings
#if !CORE_CLR #if !CORE_CLR
return StringComparer.InvariantCulture.Compare((string)this, (string)other); return StringComparer.InvariantCulture.Compare((string)this, (string)other);
#else #else
var compareInfo = System.Globalization.CultureInfo.InvariantCulture.CompareInfo; var compareInfo = System.Globalization.CultureInfo.InvariantCulture.CompareInfo;
return compareInfo.Compare((string)this, (string)other, System.Globalization.CompareOptions.Ordinal); return compareInfo.Compare((string)this, (string)other, System.Globalization.CompareOptions.Ordinal);
#endif #endif
} }
catch(Exception ex) catch(Exception ex)
{ {
ConnectionMultiplexer.TraceWithoutContext(ex.Message); ConnectionMultiplexer.TraceWithoutContext(ex.Message);
} }
// if all else fails, consider equivalent // if all else fails, consider equivalent
return 0; return 0;
} }
int IComparable.CompareTo(object obj) int IComparable.CompareTo(object obj)
{ {
if (obj is RedisValue) return CompareTo((RedisValue)obj); if (obj is RedisValue) return CompareTo((RedisValue)obj);
if (obj is long) return CompareTo((RedisValue)(long)obj); if (obj is long) return CompareTo((RedisValue)(long)obj);
if (obj is double) return CompareTo((RedisValue)(double)obj); if (obj is double) return CompareTo((RedisValue)(double)obj);
if (obj is string) return CompareTo((RedisValue)(string)obj); if (obj is string) return CompareTo((RedisValue)(string)obj);
if (obj is byte[]) return CompareTo((RedisValue)(byte[])obj); if (obj is byte[]) return CompareTo((RedisValue)(byte[])obj);
if (obj is bool) return CompareTo((RedisValue)(bool)obj); if (obj is bool) return CompareTo((RedisValue)(bool)obj);
return -1; return -1;
} }
/// <summary> /// <summary>
/// Creates a new RedisValue from an Int32 /// Creates a new RedisValue from an Int32
/// </summary> /// </summary>
public static implicit operator RedisValue(int value) public static implicit operator RedisValue(int value)
{ {
return new RedisValue(value, IntegerSentinel); return new RedisValue(value, IntegerSentinel);
} }
/// <summary> /// <summary>
/// Creates a new RedisValue from a nullable Int32 /// Creates a new RedisValue from a nullable Int32
/// </summary> /// </summary>
public static implicit operator RedisValue(int? value) public static implicit operator RedisValue(int? value)
{ {
return value == null ? Null : (RedisValue)value.GetValueOrDefault(); return value == null ? Null : (RedisValue)value.GetValueOrDefault();
} }
/// <summary> /// <summary>
/// Creates a new RedisValue from an Int64 /// Creates a new RedisValue from an Int64
/// </summary> /// </summary>
public static implicit operator RedisValue(long value) public static implicit operator RedisValue(long value)
{ {
return new RedisValue(value, IntegerSentinel); return new RedisValue(value, IntegerSentinel);
} }
/// <summary> /// <summary>
/// Creates a new RedisValue from a nullable Int64 /// Creates a new RedisValue from a nullable Int64
/// </summary> /// </summary>
public static implicit operator RedisValue(long? value) public static implicit operator RedisValue(long? value)
{ {
return value == null ? Null : (RedisValue)value.GetValueOrDefault(); return value == null ? Null : (RedisValue)value.GetValueOrDefault();
} }
/// <summary> /// <summary>
/// Creates a new RedisValue from a Double /// Creates a new RedisValue from a Double
/// </summary> /// </summary>
public static implicit operator RedisValue(double value) public static implicit operator RedisValue(double value)
{ {
return Format.ToString(value); return Format.ToString(value);
} }
/// <summary> /// <summary>
/// Creates a new RedisValue from a nullable Double /// Creates a new RedisValue from a nullable Double
/// </summary> /// </summary>
public static implicit operator RedisValue(double? value) public static implicit operator RedisValue(double? value)
{ {
return value == null ? Null : (RedisValue)value.GetValueOrDefault(); return value == null ? Null : (RedisValue)value.GetValueOrDefault();
} }
/// <summary> /// <summary>
/// Creates a new RedisValue from a String /// Creates a new RedisValue from a String
/// </summary> /// </summary>
public static implicit operator RedisValue(string value) public static implicit operator RedisValue(string value)
{ {
byte[] blob; byte[] blob;
if (value == null) blob = null; if (value == null) blob = null;
else if (value.Length == 0) blob = EmptyByteArr; else if (value.Length == 0) blob = EmptyByteArr;
else blob = Encoding.UTF8.GetBytes(value); else blob = Encoding.UTF8.GetBytes(value);
return new RedisValue(0, blob); return new RedisValue(0, blob);
} }
/// <summary> /// <summary>
/// Creates a new RedisValue from a Byte[] /// Creates a new RedisValue from a Byte[]
/// </summary> /// </summary>
public static implicit operator RedisValue(byte[] value) public static implicit operator RedisValue(byte[] value)
{ {
byte[] blob; byte[] blob;
if (value == null) blob = null; if (value == null) blob = null;
else if (value.Length == 0) blob = EmptyByteArr; else if (value.Length == 0) blob = EmptyByteArr;
else blob = value; else blob = value;
return new RedisValue(0, blob); return new RedisValue(0, blob);
} }
/// <summary> /// <summary>
/// Creates a new RedisValue from a Boolean /// Creates a new RedisValue from a Boolean
/// </summary> /// </summary>
public static implicit operator RedisValue(bool value) public static implicit operator RedisValue(bool value)
{ {
return new RedisValue(value ? 1 : 0, IntegerSentinel); return new RedisValue(value ? 1 : 0, IntegerSentinel);
} }
/// <summary> /// <summary>
/// Creates a new RedisValue from a nullable Boolean /// Creates a new RedisValue from a nullable Boolean
/// </summary> /// </summary>
public static implicit operator RedisValue(bool? value) public static implicit operator RedisValue(bool? value)
{ {
return value == null ? Null : (RedisValue)value.GetValueOrDefault(); return value == null ? Null : (RedisValue)value.GetValueOrDefault();
} }
/// <summary> /// <summary>
/// Converts the value to a Boolean /// Converts the value to a Boolean
/// </summary> /// </summary>
public static explicit operator bool (RedisValue value) public static explicit operator bool (RedisValue value)
{ {
switch((long)value) switch((long)value)
{ {
case 0: return false; case 0: return false;
case 1: return true; case 1: return true;
default: throw new InvalidCastException(); default: throw new InvalidCastException();
} }
} }
/// <summary> /// <summary>
/// Converts the value to an Int32 /// Converts the value to an Int32
/// </summary> /// </summary>
public static explicit operator int(RedisValue value) public static explicit operator int(RedisValue value)
{ {
checked checked
{ {
return (int)(long)value; return (int)(long)value;
} }
} }
/// <summary> /// <summary>
/// Converts the value to an Int64 /// Converts the value to an Int64
/// </summary> /// </summary>
public static explicit operator long(RedisValue value) public static explicit operator long(RedisValue value)
{ {
var blob = value.valueBlob; var blob = value.valueBlob;
if (blob == IntegerSentinel) return value.valueInt64; if (blob == IntegerSentinel) return value.valueInt64;
if (blob == null) return 0; // in redis, an arithmetic zero is kinda the same thing as not-exists (think "incr") if (blob == null) return 0; // in redis, an arithmetic zero is kinda the same thing as not-exists (think "incr")
long i64; long i64;
if (TryParseInt64(blob, 0, blob.Length, out i64)) return i64; if (TryParseInt64(blob, 0, blob.Length, out i64)) return i64;
throw new InvalidCastException(); throw new InvalidCastException();
} }
/// <summary> /// <summary>
/// Converts the value to a Double /// Converts the value to a Double
/// </summary> /// </summary>
public static explicit operator double (RedisValue value) public static explicit operator double (RedisValue value)
{ {
var blob = value.valueBlob; var blob = value.valueBlob;
if (blob == IntegerSentinel) return value.valueInt64; if (blob == IntegerSentinel) return value.valueInt64;
if (blob == null) return 0; // in redis, an arithmetic zero is kinda the same thing as not-exists (think "incr") if (blob == null) return 0; // in redis, an arithmetic zero is kinda the same thing as not-exists (think "incr")
double r8; double r8;
if (TryParseDouble(blob, out r8)) return r8; if (TryParseDouble(blob, out r8)) return r8;
throw new InvalidCastException(); throw new InvalidCastException();
} }
static bool TryParseDouble(byte[] blob, out double value) static bool TryParseDouble(byte[] blob, out double value)
{ {
// simple integer? // simple integer?
if (blob.Length == 1 && blob[0] >= '0' && blob[0] <= '9') if (blob.Length == 1 && blob[0] >= '0' && blob[0] <= '9')
{ {
value = blob[0] - '0'; value = blob[0] - '0';
return true; return true;
} }
return Format.TryParseDouble(Encoding.UTF8.GetString(blob), out value); return Format.TryParseDouble(Encoding.UTF8.GetString(blob), out value);
} }
/// <summary> /// <summary>
/// Converts the value to a nullable Double /// Converts the value to a nullable Double
/// </summary> /// </summary>
public static explicit operator double? (RedisValue value) public static explicit operator double? (RedisValue value)
{ {
if (value.valueBlob == null) return null; if (value.valueBlob == null) return null;
return (double)value; return (double)value;
} }
/// <summary> /// <summary>
/// Converts the value to a nullable Int64 /// Converts the value to a nullable Int64
/// </summary> /// </summary>
public static explicit operator long? (RedisValue value) public static explicit operator long? (RedisValue value)
{ {
if (value.valueBlob == null) return null; if (value.valueBlob == null) return null;
return (long)value; return (long)value;
} }
/// <summary> /// <summary>
/// Converts the value to a nullable Int32 /// Converts the value to a nullable Int32
/// </summary> /// </summary>
public static explicit operator int? (RedisValue value) public static explicit operator int? (RedisValue value)
{ {
if (value.valueBlob == null) return null; if (value.valueBlob == null) return null;
return (int)value; return (int)value;
} }
/// <summary> /// <summary>
/// Converts the value to a nullable Boolean /// Converts the value to a nullable Boolean
/// </summary> /// </summary>
public static explicit operator bool? (RedisValue value) public static explicit operator bool? (RedisValue value)
{ {
if (value.valueBlob == null) return null; if (value.valueBlob == null) return null;
return (bool)value; return (bool)value;
} }
/// <summary> /// <summary>
/// Converts the value to a String /// Converts the value to a String
/// </summary> /// </summary>
public static implicit operator string(RedisValue value) public static implicit operator string(RedisValue value)
{ {
var valueBlob = value.valueBlob; var valueBlob = value.valueBlob;
if (valueBlob == IntegerSentinel) if (valueBlob == IntegerSentinel)
return Format.ToString(value.valueInt64); return Format.ToString(value.valueInt64);
if (valueBlob == null) return null; if (valueBlob == null) return null;
if (valueBlob.Length == 0) return ""; if (valueBlob.Length == 0) return "";
try try
{ {
return Encoding.UTF8.GetString(valueBlob); return Encoding.UTF8.GetString(valueBlob);
} }
catch catch
{ {
return BitConverter.ToString(valueBlob); return BitConverter.ToString(valueBlob);
} }
} }
/// <summary> /// <summary>
/// Converts the value to a byte[] /// Converts the value to a byte[]
/// </summary> /// </summary>
public static implicit operator byte[](RedisValue value) public static implicit operator byte[](RedisValue value)
{ {
var valueBlob = value.valueBlob; var valueBlob = value.valueBlob;
if (valueBlob == IntegerSentinel) if (valueBlob == IntegerSentinel)
{ {
return Encoding.UTF8.GetBytes(Format.ToString(value.valueInt64)); return Encoding.UTF8.GetBytes(Format.ToString(value.valueInt64));
} }
return valueBlob; return valueBlob;
} }
TypeCode IConvertible.GetTypeCode() => TypeCode.Object; TypeCode IConvertible.GetTypeCode() => TypeCode.Object;
bool IConvertible.ToBoolean(IFormatProvider provider) => (bool)this; bool IConvertible.ToBoolean(IFormatProvider provider) => (bool)this;
byte IConvertible.ToByte(IFormatProvider provider) => (byte)this; byte IConvertible.ToByte(IFormatProvider provider) => (byte)this;
char IConvertible.ToChar(IFormatProvider provider) => (char)this; char IConvertible.ToChar(IFormatProvider provider) => (char)this;
DateTime IConvertible.ToDateTime(IFormatProvider provider) => DateTime.Parse((string)this, provider); DateTime IConvertible.ToDateTime(IFormatProvider provider) => DateTime.Parse((string)this, provider);
decimal IConvertible.ToDecimal(IFormatProvider provider) => (decimal)this; decimal IConvertible.ToDecimal(IFormatProvider provider) => (decimal)this;
double IConvertible.ToDouble(IFormatProvider provider) => (double)this; double IConvertible.ToDouble(IFormatProvider provider) => (double)this;
short IConvertible.ToInt16(IFormatProvider provider) => (short)this; short IConvertible.ToInt16(IFormatProvider provider) => (short)this;
int IConvertible.ToInt32(IFormatProvider provider) => (int)this; int IConvertible.ToInt32(IFormatProvider provider) => (int)this;
long IConvertible.ToInt64(IFormatProvider provider) => (long)this; long IConvertible.ToInt64(IFormatProvider provider) => (long)this;
sbyte IConvertible.ToSByte(IFormatProvider provider) => (sbyte)this; sbyte IConvertible.ToSByte(IFormatProvider provider) => (sbyte)this;
float IConvertible.ToSingle(IFormatProvider provider) => (float)this; float IConvertible.ToSingle(IFormatProvider provider) => (float)this;
string IConvertible.ToString(IFormatProvider provider) => (string)this; string IConvertible.ToString(IFormatProvider provider) => (string)this;
object IConvertible.ToType(Type conversionType, IFormatProvider provider) object IConvertible.ToType(Type conversionType, IFormatProvider provider)
{ {
if (conversionType== null) throw new ArgumentNullException(nameof(conversionType)); if (conversionType== null) throw new ArgumentNullException(nameof(conversionType));
if (conversionType== typeof(byte[])) return (byte[])this; if (conversionType== typeof(byte[])) return (byte[])this;
if (conversionType == typeof(RedisValue)) return this; if (conversionType == typeof(RedisValue)) return this;
switch(conversionType.GetTypeCode()) switch(conversionType.GetTypeCode())
{ {
case TypeCode.Boolean: return (bool)this; case TypeCode.Boolean: return (bool)this;
case TypeCode.Byte: return (byte)this; case TypeCode.Byte: return (byte)this;
case TypeCode.Char: return (char)this; case TypeCode.Char: return (char)this;
case TypeCode.DateTime: return DateTime.Parse((string)this, provider); case TypeCode.DateTime: return DateTime.Parse((string)this, provider);
case TypeCode.Decimal: return (decimal)this; case TypeCode.Decimal: return (decimal)this;
case TypeCode.Double: return (double)this; case TypeCode.Double: return (double)this;
case TypeCode.Int16: return (short)this; case TypeCode.Int16: return (short)this;
case TypeCode.Int32: return (int)this; case TypeCode.Int32: return (int)this;
case TypeCode.Int64: return (long)this; case TypeCode.Int64: return (long)this;
case TypeCode.SByte: return (sbyte)this; case TypeCode.SByte: return (sbyte)this;
case TypeCode.Single: return (float)this; case TypeCode.Single: return (float)this;
case TypeCode.String: return (string)this; case TypeCode.String: return (string)this;
case TypeCode.UInt16: return (ushort)this; case TypeCode.UInt16: return (ushort)this;
case TypeCode.UInt32: return (uint)this; case TypeCode.UInt32: return (uint)this;
case TypeCode.UInt64: return (long)this; case TypeCode.UInt64: return (long)this;
case TypeCode.Object: return this; case TypeCode.Object: return this;
default: default:
throw new NotSupportedException(); throw new NotSupportedException();
} }
} }
ushort IConvertible.ToUInt16(IFormatProvider provider) => (ushort)this; ushort IConvertible.ToUInt16(IFormatProvider provider) => (ushort)this;
uint IConvertible.ToUInt32(IFormatProvider provider) => (uint)this; uint IConvertible.ToUInt32(IFormatProvider provider) => (uint)this;
ulong IConvertible.ToUInt64(IFormatProvider provider) => (ulong)this; ulong IConvertible.ToUInt64(IFormatProvider provider) => (ulong)this;
/// <summary> /// <summary>
/// Convert to a long if possible, returning true. /// Convert to a long if possible, returning true.
/// ///
/// Returns false otherwise. /// Returns false otherwise.
/// </summary> /// </summary>
public bool TryParse(out long val) public bool TryParse(out long val)
...@@ -621,7 +621,7 @@ public bool TryParse(out long val) ...@@ -621,7 +621,7 @@ public bool TryParse(out long val)
/// <summary> /// <summary>
/// Convert to a int if possible, returning true. /// Convert to a int if possible, returning true.
/// ///
/// Returns false otherwise. /// Returns false otherwise.
/// </summary> /// </summary>
public bool TryParse(out int val) public bool TryParse(out int val)
...@@ -639,7 +639,7 @@ public bool TryParse(out int val) ...@@ -639,7 +639,7 @@ public bool TryParse(out int val)
/// <summary> /// <summary>
/// Convert to a double if possible, returning true. /// Convert to a double if possible, returning true.
/// ///
/// Returns false otherwise. /// Returns false otherwise.
/// </summary> /// </summary>
public bool TryParse(out double val) public bool TryParse(out double val)
...@@ -658,12 +658,12 @@ public bool TryParse(out double val) ...@@ -658,12 +658,12 @@ public bool TryParse(out double val)
} }
return TryParseDouble(blob, out val); return TryParseDouble(blob, out val);
} }
} }
internal static class ReflectionExtensions internal static class ReflectionExtensions
{ {
#if CORE_CLR #if CORE_CLR
internal static TypeCode GetTypeCode(this Type type) internal static TypeCode GetTypeCode(this Type type)
{ {
if (type == null) return TypeCode.Empty; if (type == null) return TypeCode.Empty;
...@@ -702,6 +702,6 @@ internal static TypeCode GetTypeCode(this Type type) ...@@ -702,6 +702,6 @@ internal static TypeCode GetTypeCode(this Type type)
{ {
return Type.GetTypeCode(type); return Type.GetTypeCode(type);
} }
#endif #endif
} }
} }
...@@ -140,7 +140,8 @@ public virtual bool SetResult(PhysicalConnection connection, Message message, Ra ...@@ -140,7 +140,8 @@ public virtual bool SetResult(PhysicalConnection connection, Message message, Ra
var bridge = connection.Bridge; var bridge = connection.Bridge;
var server = bridge.ServerEndPoint; var server = bridge.ServerEndPoint;
bool log = !message.IsInternalCall; bool log = !message.IsInternalCall;
bool isMoved = result.AssertStarts(MOVED); bool isMoved = result.AssertStarts(MOVED);
string err = string.Empty;
if (isMoved || result.AssertStarts(ASK)) if (isMoved || result.AssertStarts(ASK))
{ {
message.SetResponseReceived(); message.SetResponseReceived();
...@@ -151,21 +152,29 @@ public virtual bool SetResult(PhysicalConnection connection, Message message, Ra ...@@ -151,21 +152,29 @@ public virtual bool SetResult(PhysicalConnection connection, Message message, Ra
EndPoint endpoint; EndPoint endpoint;
if (Format.TryParseInt32(parts[1], out hashSlot) && if (Format.TryParseInt32(parts[1], out hashSlot) &&
(endpoint = Format.TryParseEndPoint(parts[2])) != null) (endpoint = Format.TryParseEndPoint(parts[2])) != null)
{ {
// no point sending back to same server, and no point sending to a dead server // no point sending back to same server, and no point sending to a dead server
if (!Equals(server.EndPoint, endpoint)) if (!Equals(server.EndPoint, endpoint))
{ {
if (bridge.Multiplexer.TryResend(hashSlot, message, endpoint, isMoved)) if (bridge.Multiplexer.TryResend(hashSlot, message, endpoint, isMoved))
{ {
connection.Multiplexer.Trace(message.Command + " re-issued to " + endpoint, isMoved ? "MOVED" : "ASK"); connection.Multiplexer.Trace(message.Command + " re-issued to " + endpoint, isMoved ? "MOVED" : "ASK");
return false; return false;
}
else
{
err = string.Format("Endpoint {0} serving hashslot {1} is not reachable at this point of time. Please check connectTimeout value. If it is low, try increasing it to give the ConnectionMultiplexer a chance to recover from the network disconnect.", endpoint, hashSlot);
} }
} }
} }
}
if (string.IsNullOrWhiteSpace(err))
{
err = result.GetString();
} }
string err = result.GetString();
if (log) if (log)
{ {
bridge.Multiplexer.OnErrorMessage(server.EndPoint, err); bridge.Multiplexer.OnErrorMessage(server.EndPoint, err);
......
...@@ -101,7 +101,8 @@ internal Exception LastException ...@@ -101,7 +101,8 @@ internal Exception LastException
//check if subscription endpoint has a better lastexception //check if subscription endpoint has a better lastexception
if (tmp2 != null && tmp2.LastException != null) if (tmp2 != null && tmp2.LastException != null)
{ {
if (!tmp2.LastException.Data["Redis-FailureType"].ToString().Equals(ConnectionFailureType.UnableToConnect.ToString())) var failureType = tmp2.LastException.Data["Redis-FailureType"];
if (failureType != null && !failureType.ToString().Equals(ConnectionFailureType.UnableToConnect.ToString()))
{ {
return tmp2.LastException; return tmp2.LastException;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment