Commit 2712ccf9 authored by Marc Gravell's avatar Marc Gravell

Merge branch 'netcore' of https://github.com/jeremymeng/StackExchange.Redis into jeremymeng-netcore

parents 9a4e4087 53d5028b
.hg .hg
bin bin
bin.snk bin.snk
obj obj
*.suo *.suo
*.user *.user
*.nupkg *.nupkg
packages/NuGet.CommandLine.* packages/NuGet.CommandLine.*
*.sln.docstates *.sln.docstates
_ReSharper.* _ReSharper.*
Mono/ Mono/
*.sln.ide *.sln.ide
*.rdb *.rdb
*.aof *.aof
*.orig *.orig
redis-cli.exe redis-cli.exe
Redis Configs/*.dat Redis Configs/*.dat
RedisQFork*.dat RedisQFork*.dat
StackExchange.Redis.*.zip StackExchange.Redis.*.zip
\ No newline at end of file .vs/
*.lock.json
\ No newline at end of file
...@@ -35,9 +35,17 @@ static void MassiveBulkOpsAsync(int AsyncOpsQty, bool preserveOrder, bool withCo ...@@ -35,9 +35,17 @@ static void MassiveBulkOpsAsync(int AsyncOpsQty, bool preserveOrder, bool withCo
var conn = muxer.GetDatabase(); var conn = muxer.GetDatabase();
muxer.Wait(conn.PingAsync()); muxer.Wait(conn.PingAsync());
int number = 0;
Action<Task> nonTrivial = delegate Action<Task> nonTrivial = delegate
{ {
#if !DNXCORE50
Thread.SpinWait(5); Thread.SpinWait(5);
#else
for (int i = 0; i < 50; i++)
{
number++;
}
#endif
}; };
var watch = Stopwatch.StartNew(); var watch = Stopwatch.StartNew();
for (int i = 0; i <= AsyncOpsQty; i++) for (int i = 0; i <= AsyncOpsQty; i++)
......
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>9d83baba-a92e-495f-bf63-deb4f6b09355</ProjectGuid>
<RootNamespace>BasicTest_dnxcore50</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>
\ No newline at end of file
{
"version": "1.0.0-*",
"description": "StackExchange.Redis.BasicTest dnxcore50",
"authors": [ "jeremymeng" ],
"tags": [ "" ],
"projectUrl": "",
"licenseUrl": "",
"compile": [
"../BasicTest/Program.cs"
],
"dependencies": {
"StackExchange.Redis": "1.1.0-*"
},
"commands": {
"run": "BasicTest_dnxcore50"
},
"configurations": {
"Debug": {
"compilationOptions": {
"define": [ "DEBUG", "TRACE" ]
}
},
"Release": {
"compilationOptions": {
"define": [ "TRACE" ]
}
}
},
"frameworks": {
"dnxcore50": {
"dependencies": {
"System.Console": "4.0.0-beta-23409"
}
}
}
}
...@@ -122,25 +122,36 @@ public void CanOpenSecuredConnection() ...@@ -122,25 +122,36 @@ public void CanOpenSecuredConnection()
} }
} }
[Test, ExpectedException(typeof(RedisConnectionException))] [Test]
public void CanNotOpenNonsenseConnection_IP() public void CanNotOpenNonsenseConnection_IP()
{ {
var log = new StringWriter(); Assert.Throws<RedisConnectionException>(() =>
try { {
using (var conn = ConnectionMultiplexer.Connect(Config.LocalHost + ":6500")) { } var log = new StringWriter();
} finally { try {
Console.WriteLine(log); using (var conn = ConnectionMultiplexer.Connect(Config.LocalHost + ":6500")) { }
} }
finally {
Console.WriteLine(log);
}
});
} }
[Test, ExpectedException(typeof(RedisConnectionException))]
[Test]
public void CanNotOpenNonsenseConnection_DNS() public void CanNotOpenNonsenseConnection_DNS()
{ {
var log = new StringWriter(); Assert.Throws<RedisConnectionException>(() =>
try { {
using (var conn = ConnectionMultiplexer.Connect("doesnot.exist.ds.aasd981230d.com:6500", log)) { } var log = new StringWriter();
} finally { try
Console.WriteLine(log); {
} using (var conn = ConnectionMultiplexer.Connect("doesnot.exist.ds.aasd981230d.com:6500", log)) { }
}
finally
{
Console.WriteLine(log);
}
});
} }
[Test] [Test]
......
...@@ -55,28 +55,33 @@ public void ExecuteWithEmptyStartingPoint() ...@@ -55,28 +55,33 @@ public void ExecuteWithEmptyStartingPoint()
} }
} }
[Test, ExpectedException(typeof(RedisServerException), ExpectedMessage = "WRONGTYPE Operation against a key holding the wrong kind of value")] [Test]
public void ExecuteWithNonHashStartingPoint() public void ExecuteWithNonHashStartingPoint()
{ {
using (var muxer = Config.GetUnsecuredConnection()) Assert.Throws<RedisConnectionException>(() =>
{ {
var conn = muxer.GetDatabase(0); using (var muxer = Config.GetUnsecuredConnection())
var task = new { priority = 3 }; {
conn.KeyDeleteAsync("item:1"); var conn = muxer.GetDatabase(0);
conn.StringSetAsync("item:1", "not a hash"); var task = new { priority = 3 };
conn.HashSetAsync("item:1", "priority", task.priority.ToString()); conn.KeyDeleteAsync("item:1");
conn.StringSetAsync("item:1", "not a hash");
conn.HashSetAsync("item:1", "priority", task.priority.ToString());
var taskResult = conn.HashGetAsync("item:1", "priority"); var taskResult = conn.HashGetAsync("item:1", "priority");
try try
{ {
conn.Wait(taskResult); conn.Wait(taskResult);
Assert.Fail(); Assert.Fail();
} catch(AggregateException ex) }
{ catch (AggregateException ex)
throw ex.InnerExceptions[0]; {
throw ex.InnerExceptions[0];
}
} }
} },
message: "WRONGTYPE Operation against a key holding the wrong kind of value");
} }
} }
} }
...@@ -44,9 +44,9 @@ ...@@ -44,9 +44,9 @@
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet> <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="nunit.framework, Version=2.6.4.14350, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL"> <Reference Include="nunit.framework, Version=3.0.5797.27534, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion> <HintPath>..\packages\NUnit.3.0.0\lib\net45\nunit.framework.dll</HintPath>
<HintPath>..\packages\NUnit.2.6.4\lib\nunit.framework.dll</HintPath> <Private>True</Private>
</Reference> </Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Core" /> <Reference Include="System.Core" />
......
...@@ -100,7 +100,6 @@ where Attribute.IsDefined(method, typeof(TestAttribute)) ...@@ -100,7 +100,6 @@ where Attribute.IsDefined(method, typeof(TestAttribute))
foreach (var test in tests) foreach (var test in tests)
{ {
var expectedFail = Attribute.GetCustomAttribute(test, typeof(ExpectedExceptionAttribute)) as ExpectedExceptionAttribute;
Console.Write(test.Name + ": "); Console.Write(test.Name + ": ");
Exception err = null; Exception err = null;
...@@ -131,35 +130,6 @@ where Attribute.IsDefined(method, typeof(TestAttribute)) ...@@ -131,35 +130,6 @@ where Attribute.IsDefined(method, typeof(TestAttribute))
err = ((AggregateException)err).InnerExceptions[0]; err = ((AggregateException)err).InnerExceptions[0];
} }
if (expectedFail != null)
{
if (err == null)
{
err = new NUnit.Framework.AssertionException("failed to fail");
}
else
{
int issues = 0;
if (expectedFail.ExpectedException != null && !expectedFail.ExpectedException.IsAssignableFrom(err.GetType()))
{
issues++;
}
if (expectedFail.ExpectedExceptionName != null && err.GetType().FullName != expectedFail.ExpectedExceptionName)
{
issues++;
}
if (expectedFail.ExpectedMessage != null && err.Message != expectedFail.ExpectedMessage)
{
issues++;
}
if (issues == 0) err = null;
else
{
err = new InvalidOperationException("Failed in a different way", err);
}
}
}
if (err == null) if (err == null)
{ {
Console.WriteLine("pass"); Console.WriteLine("pass");
......
...@@ -264,21 +264,26 @@ public void NonAsciiScripts() ...@@ -264,21 +264,26 @@ public void NonAsciiScripts()
} }
} }
[Test, ExpectedException(typeof(RedisServerException), ExpectedMessage = "oops")] [Test]
public void ScriptThrowsError() public void ScriptThrowsError()
{ {
using (var muxer = GetScriptConn()) Assert.Throws<RedisServerException>(() =>
{ {
var conn = muxer.GetDatabase(0); using (var muxer = GetScriptConn())
var result = conn.ScriptEvaluateAsync("return redis.error_reply('oops')", null, null);
try
{ {
conn.Wait(result); var conn = muxer.GetDatabase(0);
} catch(AggregateException ex) var result = conn.ScriptEvaluateAsync("return redis.error_reply('oops')", null, null);
{ try
throw ex.InnerExceptions[0]; {
conn.Wait(result);
}
catch (AggregateException ex)
{
throw ex.InnerExceptions[0];
}
} }
} },
message: "oops");
} }
[Test] [Test]
......
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="NUnit" version="2.6.4" targetFramework="net45" /> <package id="NUnit" version="3.0.0" targetFramework="net45" />
</packages> </packages>
\ No newline at end of file
This diff is collapsed.
using System; #if FEATURE_MOQ
using System;
using Moq; using Moq;
using NUnit.Framework; using NUnit.Framework;
using StackExchange.Redis.KeyspaceIsolation; using StackExchange.Redis.KeyspaceIsolation;
...@@ -12,7 +13,8 @@ public sealed class BatchWrapperTests ...@@ -12,7 +13,8 @@ public sealed class BatchWrapperTests
private Mock<IBatch> mock; private Mock<IBatch> mock;
private BatchWrapper wrapper; private BatchWrapper wrapper;
[TestFixtureSetUp] //[TestFixtureSetUp]
[OneTimeSetUpAttribute]
public void Initialize() public void Initialize()
{ {
mock = new Mock<IBatch>(); mock = new Mock<IBatch>();
...@@ -27,3 +29,4 @@ public void Execute() ...@@ -27,3 +29,4 @@ public void Execute()
} }
} }
} }
#endif
\ No newline at end of file
This diff is collapsed.
...@@ -125,13 +125,16 @@ public void ClientName() ...@@ -125,13 +125,16 @@ public void ClientName()
} }
[Test] [Test]
[ExpectedException(typeof(RedisCommandException), ExpectedMessage = "This operation has been disabled in the command-map and cannot be used: CONFIG")]
public void ReadConfigWithConfigDisabled() public void ReadConfigWithConfigDisabled()
{ {
using (var muxer = Create(allowAdmin: true, disabledCommands: new[] { "config", "info" })) using (var muxer = Create(allowAdmin: true, disabledCommands: new[] { "config", "info" }))
{ {
var conn = GetServer(muxer); var conn = GetServer(muxer);
var all = conn.ConfigGet(); Assert.Throws<RedisCommandException>(() =>
{
var all = conn.ConfigGet();
},
"This operation has been disabled in the command-map and cannot be used: CONFIG");
} }
} }
[Test] [Test]
...@@ -144,7 +147,11 @@ public void ReadConfig() ...@@ -144,7 +147,11 @@ public void ReadConfig()
var all = conn.ConfigGet(); var all = conn.ConfigGet();
Assert.IsTrue(all.Length > 0, "any"); Assert.IsTrue(all.Length > 0, "any");
#if !DNXCORE50
var pairs = all.ToDictionary(x => (string)x.Key, x => (string)x.Value, StringComparer.InvariantCultureIgnoreCase); var pairs = all.ToDictionary(x => (string)x.Key, x => (string)x.Value, StringComparer.InvariantCultureIgnoreCase);
#else
var pairs = all.ToDictionary(x => (string)x.Key, x => (string)x.Value, StringComparer.OrdinalIgnoreCase);
#endif
Assert.AreEqual(all.Length, pairs.Count); Assert.AreEqual(all.Length, pairs.Count);
Assert.IsTrue(pairs.ContainsKey("timeout"), "timeout"); Assert.IsTrue(pairs.ContainsKey("timeout"), "timeout");
...@@ -157,7 +164,7 @@ public void ReadConfig() ...@@ -157,7 +164,7 @@ public void ReadConfig()
} }
[Test] [Test]
public async void TestConfigureAsync() public async System.Threading.Tasks.Task TestConfigureAsync()
{ {
using(var muxer = Create()) using(var muxer = Create())
{ {
......
using System; #if FEATURE_MOQ
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq.Expressions; using System.Linq.Expressions;
using System.Net; using System.Net;
...@@ -15,7 +16,8 @@ public sealed class DatabaseWrapperTests ...@@ -15,7 +16,8 @@ public sealed class DatabaseWrapperTests
private Mock<IDatabase> mock; private Mock<IDatabase> mock;
private DatabaseWrapper wrapper; private DatabaseWrapper wrapper;
[TestFixtureSetUp] //[TestFixtureSetUp]
[OneTimeSetUp]
public void Initialize() public void Initialize()
{ {
mock = new Mock<IDatabase>(); mock = new Mock<IDatabase>();
...@@ -289,10 +291,9 @@ public void KeyPersist() ...@@ -289,10 +291,9 @@ public void KeyPersist()
} }
[Test] [Test]
[ExpectedException(typeof(NotSupportedException))]
public void KeyRandom() public void KeyRandom()
{ {
wrapper.KeyRandom(); Assert.Throws<NotSupportedException>(() => wrapper.KeyRandom());
} }
[Test] [Test]
...@@ -933,3 +934,4 @@ public void StringSetRange() ...@@ -933,3 +934,4 @@ public void StringSetRange()
} }
} }
} }
#endif
\ No newline at end of file
...@@ -23,15 +23,21 @@ public void UnkonwnKeywordHandling_Ignore() ...@@ -23,15 +23,21 @@ public void UnkonwnKeywordHandling_Ignore()
{ {
var options = ConfigurationOptions.Parse("ssl2=true", true); var options = ConfigurationOptions.Parse("ssl2=true", true);
} }
[Test, ExpectedException(typeof(ArgumentException), ExpectedMessage = "Keyword 'ssl2' is not supported")] [Test]
public void UnkonwnKeywordHandling_ExplicitFail() public void UnkonwnKeywordHandling_ExplicitFail()
{ {
var options = ConfigurationOptions.Parse("ssl2=true", false); Assert.Throws<ArgumentException>(() => {
var options = ConfigurationOptions.Parse("ssl2=true", false);
},
"Keyword 'ssl2' is not supported");
} }
[Test, ExpectedException(typeof(ArgumentException), ExpectedMessage = "Keyword 'ssl2' is not supported")] [Test]
public void UnkonwnKeywordHandling_ImplicitFail() public void UnkonwnKeywordHandling_ImplicitFail()
{ {
var options = ConfigurationOptions.Parse("ssl2=true"); Assert.Throws<ArgumentException>(() => {
var options = ConfigurationOptions.Parse("ssl2=true");
},
"Keyword 'ssl2' is not supported");
} }
} }
} }
...@@ -9,7 +9,7 @@ public class SO25567566 : TestBase ...@@ -9,7 +9,7 @@ public class SO25567566 : TestBase
{ {
protected override string GetConfiguration() protected override string GetConfiguration()
{ {
return "127.0.0.1"; return "127.0.0.1:6379";
} }
[Test] [Test]
public async void Execute() public async void Execute()
......
...@@ -127,7 +127,7 @@ public enum TestMode ...@@ -127,7 +127,7 @@ public enum TestMode
NoMultiExec, NoMultiExec,
Twemproxy Twemproxy
} }
public IEnumerable<TestMode> TestModes() public static IEnumerable<TestMode> TestModes()
{ {
return (TestMode[])Enum.GetValues(typeof(TestMode)); return (TestMode[])Enum.GetValues(typeof(TestMode));
} }
......
...@@ -14,16 +14,19 @@ protected override string GetConfiguration() ...@@ -14,16 +14,19 @@ protected override string GetConfiguration()
return PrimaryServer + ":" + SecurePort + "," + PrimaryServer + ":" + PrimaryPort + ",password=" + SecurePassword; return PrimaryServer + ":" + SecurePort + "," + PrimaryServer + ":" + PrimaryPort + ",password=" + SecurePassword;
} }
[Test, ExpectedException(typeof(RedisCommandException), ExpectedMessage = "Command cannot be issued to a slave: FLUSHDB")] [Test]
public void CannotFlushSlave() public void CannotFlushSlave()
{ {
ConfigurationOptions config = GetMasterSlaveConfig(); Assert.Throws<RedisCommandException>(() => {
using (var conn = ConnectionMultiplexer.Connect(config)) ConfigurationOptions config = GetMasterSlaveConfig();
{ using (var conn = ConnectionMultiplexer.Connect(config))
var servers = Array.ConvertAll(conn.GetEndPoints(), e => conn.GetServer(e)); {
var slave = servers.First(x => x.IsSlave); var servers = conn.GetEndPoints().Select(e => conn.GetServer(e));
slave.FlushDatabase(); var slave = servers.First(x => x.IsSlave);
} slave.FlushDatabase();
}
},
"Command cannot be issued to a slave: FLUSHDB");
} }
[Test] [Test]
......
...@@ -17,7 +17,7 @@ public class Naming ...@@ -17,7 +17,7 @@ public class Naming
public void CheckSignatures(Type type, bool isAsync) public void CheckSignatures(Type type, bool isAsync)
{ {
// check that all methods and interfaces look appropriate for their sync/async nature // check that all methods and interfaces look appropriate for their sync/async nature
CheckName(type, isAsync); CheckName(type.GetTypeInfo(), isAsync);
var members = type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly); var members = type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly);
foreach(var member in members) foreach(var member in members)
{ {
...@@ -29,9 +29,9 @@ public void CheckSignatures(Type type, bool isAsync) ...@@ -29,9 +29,9 @@ public void CheckSignatures(Type type, bool isAsync)
[Test] [Test]
public void ShowReadOnlyOperations() public void ShowReadOnlyOperations()
{ {
var msg = typeof(ConnectionMultiplexer).Assembly.GetType("StackExchange.Redis.Message"); var msg = typeof(ConnectionMultiplexer).GetTypeInfo().Assembly.GetType("StackExchange.Redis.Message");
Assert.IsNotNull(msg, "Message"); Assert.IsNotNull(msg, "Message");
var cmd = typeof(ConnectionMultiplexer).Assembly.GetType("StackExchange.Redis.RedisCommand"); var cmd = typeof(ConnectionMultiplexer).GetTypeInfo().Assembly.GetType("StackExchange.Redis.RedisCommand");
Assert.IsNotNull(cmd, "RedisCommand"); Assert.IsNotNull(cmd, "RedisCommand");
var method = msg.GetMethod("IsMasterOnly", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public); var method = msg.GetMethod("IsMasterOnly", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
Assert.IsNotNull(method, "IsMasterOnly"); Assert.IsNotNull(method, "IsMasterOnly");
...@@ -89,7 +89,7 @@ static bool UsesKey(Type type) ...@@ -89,7 +89,7 @@ static bool UsesKey(Type type)
{ {
if (UsesKey(type.GetElementType())) return true; if (UsesKey(type.GetElementType())) return true;
} }
if(type.IsGenericType) // KVP, etc if(type.GetTypeInfo().IsGenericType) // KVP, etc
{ {
var args = type.GetGenericArguments(); var args = type.GetGenericArguments();
if (args.Any(UsesKey)) return true; if (args.Any(UsesKey)) return true;
...@@ -139,7 +139,7 @@ public void CheckSyncAsyncMethodsMatch(Type from, Type to) ...@@ -139,7 +139,7 @@ public void CheckSyncAsyncMethodsMatch(Type from, Type to)
{ {
huntType = null; huntType = null;
} }
else if (method.ReturnType.IsSubclassOf(typeof(Task))) else if (method.ReturnType.GetTypeInfo().IsSubclassOf(typeof(Task)))
{ {
huntType = method.ReturnType.GetGenericArguments()[0]; huntType = method.ReturnType.GetGenericArguments()[0];
} }
...@@ -148,9 +148,14 @@ public void CheckSyncAsyncMethodsMatch(Type from, Type to) ...@@ -148,9 +148,14 @@ public void CheckSyncAsyncMethodsMatch(Type from, Type to)
huntType = typeof(Task<>).MakeGenericType(method.ReturnType); huntType = typeof(Task<>).MakeGenericType(method.ReturnType);
} }
var pFrom = method.GetParameters(); var pFrom = method.GetParameters();
Type[] args = Array.ConvertAll(pFrom, x => x.ParameterType); Type[] args = pFrom.Select(x => x.ParameterType).ToArray();
Assert.AreEqual(typeof(CommandFlags), args.Last()); Assert.AreEqual(typeof(CommandFlags), args.Last());
#if !DNXCORE50
var found = to.GetMethod(huntName, flags, null, method.CallingConvention, args, null); var found = to.GetMethod(huntName, flags, null, method.CallingConvention, args, null);
#else
var found = to.GetMethods(flags)
.SingleOrDefault(m => m.Name == huntName && m.HasMatchingParameterTypes(args));
#endif
Assert.IsNotNull(found, "Found " + name + ", no " + huntName); Assert.IsNotNull(found, "Found " + name + ", no " + huntName);
var pTo = found.GetParameters(); var pTo = found.GetParameters();
...@@ -166,16 +171,24 @@ public void CheckSyncAsyncMethodsMatch(Type from, Type to) ...@@ -166,16 +171,24 @@ public void CheckSyncAsyncMethodsMatch(Type from, Type to)
Console.WriteLine("Validated: {0} ({1} methods)", from.Name, count); Console.WriteLine("Validated: {0} ({1} methods)", from.Name, count);
} }
static readonly Type ignoreType = typeof(ConnectionMultiplexer).Assembly.GetType("StackExchange.Redis.IgnoreNamePrefixAttribute"); static readonly Type ignoreType = typeof(ConnectionMultiplexer).GetTypeInfo().Assembly.GetType("StackExchange.Redis.IgnoreNamePrefixAttribute");
void CheckMethod(MethodInfo method, bool isAsync) void CheckMethod(MethodInfo method, bool isAsync)
{ {
#if DEBUG #if DEBUG
#if !DNXCORE50
bool ignorePrefix = ignoreType != null && Attribute.IsDefined(method, ignoreType); bool ignorePrefix = ignoreType != null && Attribute.IsDefined(method, ignoreType);
if(ignorePrefix) #else
bool ignorePrefix = ignoreType != null && method.IsDefined(ignoreType);
#endif
if (ignorePrefix)
{ {
#if !DNXCORE50
Attribute attrib = Attribute.GetCustomAttribute(method, ignoreType); Attribute attrib = Attribute.GetCustomAttribute(method, ignoreType);
if((bool)attrib.GetType().GetProperty("IgnoreEntireMethod").GetValue(attrib)) #else
Attribute attrib = method.GetCustomAttribute(ignoreType);
#endif
if ((bool)attrib.GetType().GetProperty("IgnoreEntireMethod").GetValue(attrib))
{ {
return; return;
} }
...@@ -212,4 +225,34 @@ void CheckName(MemberInfo member, bool isAsync) ...@@ -212,4 +225,34 @@ void CheckName(MemberInfo member, bool isAsync)
else Assert.IsFalse(member.Name.EndsWith("Async"), member.Name + ":Name - don't end *Async"); else Assert.IsFalse(member.Name.EndsWith("Async"), member.Name + ":Name - don't end *Async");
} }
} }
public static class ReflectionExtensions
{
#if !DNXCORE50
public static Type GetTypeInfo(this Type type)
{
return type;
}
#else
public static bool HasMatchingParameterTypes(this MethodInfo method, Type[] paramTypes)
{
var types = method.GetParameters().Select(pi => pi.ParameterType).ToArray();
if (types.Length != paramTypes.Length)
{
return false;
}
for (int i = 0; i < types.Length; i++)
{
if (types[i] != paramTypes[i])
{
return false;
}
}
return true;
}
#endif
}
} }
...@@ -2,6 +2,9 @@ ...@@ -2,6 +2,9 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
#if DNXCORE50
using System.Reflection;
#endif
using System.Threading.Tasks; using System.Threading.Tasks;
using NUnit.Framework; using NUnit.Framework;
using System.Threading; using System.Threading;
...@@ -456,11 +459,11 @@ public void LowAllocationEnumerable() ...@@ -456,11 +459,11 @@ public void LowAllocationEnumerable()
conn.WaitAll(allTasks.ToArray()); conn.WaitAll(allTasks.ToArray());
var res = conn.FinishProfiling(profiler.MyContext); var res = conn.FinishProfiling(profiler.MyContext);
Assert.IsTrue(res.GetType().IsValueType); Assert.IsTrue(res.GetType().GetTypeInfo().IsValueType);
using(var e = res.GetEnumerator()) using(var e = res.GetEnumerator())
{ {
Assert.IsTrue(e.GetType().IsValueType); Assert.IsTrue(e.GetType().GetTypeInfo().IsValueType);
Assert.IsTrue(e.MoveNext()); Assert.IsTrue(e.MoveNext());
var i = e.Current; var i = e.Current;
......
...@@ -38,17 +38,17 @@ public void ExplicitPublishMode() ...@@ -38,17 +38,17 @@ public void ExplicitPublishMode()
Thread.Sleep(1000); Thread.Sleep(1000);
pub.Publish("abcd", "efg"); pub.Publish("abcd", "efg");
Thread.Sleep(500); Thread.Sleep(500);
Assert.AreEqual(0, Thread.VolatileRead(ref a), "a1"); Assert.AreEqual(0, VolatileWrapper.Read(ref a), "a1");
Assert.AreEqual(1, Thread.VolatileRead(ref b), "b1"); Assert.AreEqual(1, VolatileWrapper.Read(ref b), "b1");
Assert.AreEqual(1, Thread.VolatileRead(ref c), "c1"); Assert.AreEqual(1, VolatileWrapper.Read(ref c), "c1");
Assert.AreEqual(1, Thread.VolatileRead(ref d), "d1"); Assert.AreEqual(1, VolatileWrapper.Read(ref d), "d1");
pub.Publish("*bcd", "efg"); pub.Publish("*bcd", "efg");
Thread.Sleep(500); Thread.Sleep(500);
Assert.AreEqual(1, Thread.VolatileRead(ref a), "a2"); Assert.AreEqual(1, VolatileWrapper.Read(ref a), "a2");
//Assert.AreEqual(1, Thread.VolatileRead(ref b), "b2"); //Assert.AreEqual(1, VolatileWrapper.Read(ref b), "b2");
//Assert.AreEqual(1, Thread.VolatileRead(ref c), "c2"); //Assert.AreEqual(1, VolatileWrapper.Read(ref c), "c2");
//Assert.AreEqual(1, Thread.VolatileRead(ref d), "d2"); //Assert.AreEqual(1, VolatileWrapper.Read(ref d), "d2");
} }
} }
...@@ -101,7 +101,7 @@ public void TestBasicPubSub(bool preserveOrder, string channelPrefix, bool wildC ...@@ -101,7 +101,7 @@ public void TestBasicPubSub(bool preserveOrder, string channelPrefix, bool wildC
{ {
Assert.AreEqual(0, received.Count); Assert.AreEqual(0, received.Count);
} }
Assert.AreEqual(0, Thread.VolatileRead(ref secondHandler)); Assert.AreEqual(0, VolatileWrapper.Read(ref secondHandler));
var count = sub.Publish(pubChannel, "def"); var count = sub.Publish(pubChannel, "def");
Ping(muxer, pub, sub, 3); Ping(muxer, pub, sub, 3);
...@@ -110,7 +110,7 @@ public void TestBasicPubSub(bool preserveOrder, string channelPrefix, bool wildC ...@@ -110,7 +110,7 @@ public void TestBasicPubSub(bool preserveOrder, string channelPrefix, bool wildC
{ {
Assert.AreEqual(1, received.Count); Assert.AreEqual(1, received.Count);
} }
Assert.AreEqual(1, Thread.VolatileRead(ref secondHandler)); Assert.AreEqual(1, VolatileWrapper.Read(ref secondHandler));
// unsubscribe from first; should still see second // unsubscribe from first; should still see second
sub.Unsubscribe(subChannel, handler1); sub.Unsubscribe(subChannel, handler1);
...@@ -120,7 +120,7 @@ public void TestBasicPubSub(bool preserveOrder, string channelPrefix, bool wildC ...@@ -120,7 +120,7 @@ public void TestBasicPubSub(bool preserveOrder, string channelPrefix, bool wildC
{ {
Assert.AreEqual(1, received.Count); Assert.AreEqual(1, received.Count);
} }
Assert.AreEqual(2, Thread.VolatileRead(ref secondHandler)); Assert.AreEqual(2, VolatileWrapper.Read(ref secondHandler));
Assert.AreEqual(1, count); Assert.AreEqual(1, count);
// unsubscribe from second; should see nothing this time // unsubscribe from second; should see nothing this time
...@@ -131,7 +131,7 @@ public void TestBasicPubSub(bool preserveOrder, string channelPrefix, bool wildC ...@@ -131,7 +131,7 @@ public void TestBasicPubSub(bool preserveOrder, string channelPrefix, bool wildC
{ {
Assert.AreEqual(1, received.Count); Assert.AreEqual(1, received.Count);
} }
Assert.AreEqual(2, Thread.VolatileRead(ref secondHandler)); Assert.AreEqual(2, VolatileWrapper.Read(ref secondHandler));
Assert.AreEqual(0, count); Assert.AreEqual(0, count);
} }
} }
...@@ -172,7 +172,7 @@ public void TestBasicPubSubFireAndForget(bool preserveOrder) ...@@ -172,7 +172,7 @@ public void TestBasicPubSubFireAndForget(bool preserveOrder)
{ {
Assert.AreEqual(0, received.Count); Assert.AreEqual(0, received.Count);
} }
Assert.AreEqual(0, Thread.VolatileRead(ref secondHandler)); Assert.AreEqual(0, VolatileWrapper.Read(ref secondHandler));
Ping(muxer, pub, sub); Ping(muxer, pub, sub);
var count = sub.Publish(key, "def", CommandFlags.FireAndForget); var count = sub.Publish(key, "def", CommandFlags.FireAndForget);
Ping(muxer, pub, sub); Ping(muxer, pub, sub);
...@@ -181,7 +181,7 @@ public void TestBasicPubSubFireAndForget(bool preserveOrder) ...@@ -181,7 +181,7 @@ public void TestBasicPubSubFireAndForget(bool preserveOrder)
{ {
Assert.AreEqual(1, received.Count); Assert.AreEqual(1, received.Count);
} }
Assert.AreEqual(1, Thread.VolatileRead(ref secondHandler)); Assert.AreEqual(1, VolatileWrapper.Read(ref secondHandler));
sub.Unsubscribe(key); sub.Unsubscribe(key);
count = sub.Publish(key, "ghi", CommandFlags.FireAndForget); count = sub.Publish(key, "ghi", CommandFlags.FireAndForget);
...@@ -247,7 +247,7 @@ public void TestPatternPubSub(bool preserveOrder) ...@@ -247,7 +247,7 @@ public void TestPatternPubSub(bool preserveOrder)
{ {
Assert.AreEqual(0, received.Count); Assert.AreEqual(0, received.Count);
} }
Assert.AreEqual(0, Thread.VolatileRead(ref secondHandler)); Assert.AreEqual(0, VolatileWrapper.Read(ref secondHandler));
var count = sub.Publish("abc", "def"); var count = sub.Publish("abc", "def");
Ping(muxer, pub, sub); Ping(muxer, pub, sub);
...@@ -256,7 +256,7 @@ public void TestPatternPubSub(bool preserveOrder) ...@@ -256,7 +256,7 @@ public void TestPatternPubSub(bool preserveOrder)
{ {
Assert.AreEqual(1, received.Count); Assert.AreEqual(1, received.Count);
} }
Assert.AreEqual(1, Thread.VolatileRead(ref secondHandler)); Assert.AreEqual(1, VolatileWrapper.Read(ref secondHandler));
sub.Unsubscribe("a*c"); sub.Unsubscribe("a*c");
count = sub.Publish("abc", "ghi"); count = sub.Publish("abc", "ghi");
...@@ -392,7 +392,7 @@ public void SubscriptionsSurviveConnectionFailure() ...@@ -392,7 +392,7 @@ public void SubscriptionsSurviveConnectionFailure()
}); });
sub.Publish(channel, "abc"); sub.Publish(channel, "abc");
sub.Ping(); sub.Ping();
Assert.AreEqual(1, Thread.VolatileRead(ref counter), "counter"); Assert.AreEqual(1, VolatileWrapper.Read(ref counter), "counter");
var server = GetServer(muxer); var server = GetServer(muxer);
Assert.AreEqual(1, server.GetCounters().Subscription.SocketCount, "sockets"); Assert.AreEqual(1, server.GetCounters().Subscription.SocketCount, "sockets");
...@@ -408,8 +408,20 @@ public void SubscriptionsSurviveConnectionFailure() ...@@ -408,8 +408,20 @@ public void SubscriptionsSurviveConnectionFailure()
#endif #endif
sub.Publish(channel, "abc"); sub.Publish(channel, "abc");
sub.Ping(); sub.Ping();
Assert.AreEqual(2, Thread.VolatileRead(ref counter), "counter"); Assert.AreEqual(2, VolatileWrapper.Read(ref counter), "counter");
} }
} }
} }
internal static class VolatileWrapper
{
public static int Read(ref int location)
{
#if !DNXCORE50
return Thread.VolatileRead(ref location);
#else
return Volatile.Read(ref location);
#endif
}
}
} }
...@@ -158,7 +158,7 @@ public void TestCallByHash() ...@@ -158,7 +158,7 @@ public void TestCallByHash()
var db = conn.GetDatabase(); var db = conn.GetDatabase();
RedisKey[] keys = { Me() }; RedisKey[] keys = { Me() };
string hexHash = string.Concat(Array.ConvertAll(hash, x => x.ToString("X2"))); string hexHash = string.Concat(hash.Select(x => x.ToString("X2")));
Assert.AreEqual("2BAB3B661081DB58BD2341920E0BA7CF5DC77B25", hexHash); Assert.AreEqual("2BAB3B661081DB58BD2341920E0BA7CF5DC77B25", hexHash);
db.ScriptEvaluate(hexHash, keys); db.ScriptEvaluate(hexHash, keys);
......
...@@ -68,14 +68,16 @@ public void Connect() ...@@ -68,14 +68,16 @@ public void Connect()
[Test] [Test]
[TestCase("wrong")] [TestCase("wrong")]
[TestCase("")] [TestCase("")]
[ExpectedException(typeof(RedisConnectionException), ExpectedMessage = "No connection is available to service this operation: PING")]
public void ConnectWithWrongPassword(string password) public void ConnectWithWrongPassword(string password)
{ {
SetExpectedAmbientFailureCount(-1); Assert.Throws<RedisConnectionException>(() => {
using (var server = Create(password: password, checkConnect: false)) SetExpectedAmbientFailureCount(-1);
{ using (var server = Create(password: password, checkConnect: false))
server.GetDatabase().Ping(); {
} server.GetDatabase().Ping();
}
},
"No connection is available to service this operation: PING");
} }
} }
} }
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
namespace StackExchange.Redis.Tests namespace StackExchange.Redis.Tests
{ {
[TestFixture, Ignore] [TestFixture, Ignore("reason?")]
public class Sentinel public class Sentinel
{ {
// TODO fill in these constants before running tests // TODO fill in these constants before running tests
...@@ -100,7 +100,7 @@ public void SentinelSlavesTest() ...@@ -100,7 +100,7 @@ public void SentinelSlavesTest()
} }
} }
[Test, Ignore] [Test, Ignore("reason?")]
public void SentinelFailoverTest() public void SentinelFailoverTest()
{ {
Server.SentinelFailover(ServiceName); Server.SentinelFailover(ServiceName);
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
<DebugType>full</DebugType> <DebugType>full</DebugType>
<Optimize>false</Optimize> <Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath> <OutputPath>bin\Debug\</OutputPath>
<DefineConstants>TRACE;DEBUG;PLAT_SAFE_CONTINUATIONS</DefineConstants> <DefineConstants>TRACE;DEBUG;PLAT_SAFE_CONTINUATIONS;FEATURE_BOOKSLEEVE;FEATURE_MOQ</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<PlatformTarget>AnyCPU</PlatformTarget> <PlatformTarget>AnyCPU</PlatformTarget>
...@@ -28,14 +28,14 @@ ...@@ -28,14 +28,14 @@
<DebugType>pdbonly</DebugType> <DebugType>pdbonly</DebugType>
<Optimize>true</Optimize> <Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath> <OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE;PLAT_SAFE_CONTINUATIONS</DefineConstants> <DefineConstants>TRACE;PLAT_SAFE_CONTINUATIONS;FEATURE_BOOKSLEEVE;FEATURE_MOQ</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Verbose|AnyCPU'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Verbose|AnyCPU'">
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>
<OutputPath>bin\Verbose\</OutputPath> <OutputPath>bin\Verbose\</OutputPath>
<DefineConstants>TRACE;DEBUG;VERBOSE</DefineConstants> <DefineConstants>TRACE;DEBUG;VERBOSE;FEATURE_BOOKSLEEVE;FEATURE_MOQ</DefineConstants>
<DebugType>full</DebugType> <DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget> <PlatformTarget>AnyCPU</PlatformTarget>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
...@@ -45,7 +45,7 @@ ...@@ -45,7 +45,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Log Output|AnyCPU'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Log Output|AnyCPU'">
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>
<OutputPath>bin\Log Output\</OutputPath> <OutputPath>bin\Log Output\</OutputPath>
<DefineConstants>TRACE;DEBUG;LOGOUTPUT</DefineConstants> <DefineConstants>TRACE;DEBUG;LOGOUTPUT;FEATURE_BOOKSLEEVE;FEATURE_MOQ</DefineConstants>
<DebugType>full</DebugType> <DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget> <PlatformTarget>AnyCPU</PlatformTarget>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
...@@ -53,7 +53,7 @@ ...@@ -53,7 +53,7 @@
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Mono|AnyCPU'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Mono|AnyCPU'">
<OutputPath>bin\Mono\</OutputPath> <OutputPath>bin\Mono\</OutputPath>
<DefineConstants>TRACE</DefineConstants> <DefineConstants>TRACE;FEATURE_BOOKSLEEVE;FEATURE_MOQ</DefineConstants>
<Optimize>true</Optimize> <Optimize>true</Optimize>
<DebugType>pdbonly</DebugType> <DebugType>pdbonly</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget> <PlatformTarget>AnyCPU</PlatformTarget>
...@@ -68,9 +68,9 @@ ...@@ -68,9 +68,9 @@
<HintPath>..\packages\Moq.4.2.1502.0911\lib\net40\Moq.dll</HintPath> <HintPath>..\packages\Moq.4.2.1502.0911\lib\net40\Moq.dll</HintPath>
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="nunit.framework, Version=2.6.4.14350, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL"> <Reference Include="nunit.framework, Version=3.0.5797.27534, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion> <HintPath>..\packages\NUnit.3.0.0\lib\net45\nunit.framework.dll</HintPath>
<HintPath>..\packages\NUnit.2.6.4\lib\nunit.framework.dll</HintPath> <Private>True</Private>
</Reference> </Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Core" /> <Reference Include="System.Core" />
......
...@@ -8,7 +8,9 @@ ...@@ -8,7 +8,9 @@
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
#if FEATURE_BOOKSLEEVE
using BookSleeve; using BookSleeve;
#endif
using NUnit.Framework; using NUnit.Framework;
namespace StackExchange.Redis.Tests namespace StackExchange.Redis.Tests
...@@ -221,6 +223,7 @@ protected static string Me([CallerMemberName] string caller = null) ...@@ -221,6 +223,7 @@ protected static string Me([CallerMemberName] string caller = null)
return caller; return caller;
} }
#if FEATURE_BOOKSLEEVE
protected static RedisConnection GetOldStyleConnection(bool open = true, bool allowAdmin = false, bool waitForOpen = false, int syncTimeout = 5000, int ioTimeout = 5000) protected static RedisConnection GetOldStyleConnection(bool open = true, bool allowAdmin = false, bool waitForOpen = false, int syncTimeout = 5000, int ioTimeout = 5000)
{ {
return GetOldStyleConnection(PrimaryServer, PrimaryPort, open, allowAdmin, waitForOpen, syncTimeout, ioTimeout); return GetOldStyleConnection(PrimaryServer, PrimaryPort, open, allowAdmin, waitForOpen, syncTimeout, ioTimeout);
...@@ -239,7 +242,7 @@ private static RedisConnection GetOldStyleConnection(string host, int port, bool ...@@ -239,7 +242,7 @@ private static RedisConnection GetOldStyleConnection(string host, int port, bool
} }
return conn; return conn;
} }
#endif
protected static TimeSpan RunConcurrent(Action work, int threads, int timeout = 10000, [CallerMemberName] string caller = null) protected static TimeSpan RunConcurrent(Action work, int threads, int timeout = 10000, [CallerMemberName] string caller = null)
{ {
if (work == null) throw new ArgumentNullException("work"); if (work == null) throw new ArgumentNullException("work");
...@@ -282,11 +285,13 @@ protected static TimeSpan RunConcurrent(Action work, int threads, int timeout = ...@@ -282,11 +285,13 @@ protected static TimeSpan RunConcurrent(Action work, int threads, int timeout =
} }
if (!allDone.WaitOne(timeout)) if (!allDone.WaitOne(timeout))
{ {
for(int i = 0; i < threads; i++) #if !DNXCORE50
for (int i = 0; i < threads; i++)
{ {
var thd = threadArr[i]; var thd = threadArr[i];
if (thd.IsAlive) thd.Abort(); if (thd.IsAlive) thd.Abort();
} }
#endif
throw new TimeoutException(); throw new TimeoutException();
} }
......
using System.Text; #if FEATURE_MOQ
using System.Text;
using Moq; using Moq;
using NUnit.Framework; using NUnit.Framework;
using StackExchange.Redis.KeyspaceIsolation; using StackExchange.Redis.KeyspaceIsolation;
...@@ -11,7 +12,7 @@ public sealed class TransactionWrapperTests ...@@ -11,7 +12,7 @@ public sealed class TransactionWrapperTests
private Mock<ITransaction> mock; private Mock<ITransaction> mock;
private TransactionWrapper wrapper; private TransactionWrapper wrapper;
[TestFixtureSetUp] [OneTimeSetUp]
public void Initialize() public void Initialize()
{ {
mock = new Mock<ITransaction>(); mock = new Mock<ITransaction>();
...@@ -89,3 +90,4 @@ public void Execute() ...@@ -89,3 +90,4 @@ public void Execute()
} }
} }
} }
#endif
\ No newline at end of file
using System; using System;
using NUnit.Framework; using NUnit.Framework;
using StackExchange.Redis.KeyspaceIsolation; using StackExchange.Redis.KeyspaceIsolation;
namespace StackExchange.Redis.Tests namespace StackExchange.Redis.Tests
{ {
[TestFixture] [TestFixture]
public class WithKeyPrefixTests : TestBase public class WithKeyPrefixTests : TestBase
{ {
[Test] [Test]
public void BlankPrefixYieldsSame_Bytes() public void BlankPrefixYieldsSame_Bytes()
{ {
using (var conn = Create()) using (var conn = Create())
{ {
var raw = conn.GetDatabase(1); var raw = conn.GetDatabase(1);
var prefixed = raw.WithKeyPrefix(new byte[0]); var prefixed = raw.WithKeyPrefix(new byte[0]);
Assert.AreSame(raw, prefixed); Assert.AreSame(raw, prefixed);
} }
} }
[Test] [Test]
public void BlankPrefixYieldsSame_String() public void BlankPrefixYieldsSame_String()
{ {
using (var conn = Create()) using (var conn = Create())
{ {
var raw = conn.GetDatabase(1); var raw = conn.GetDatabase(1);
var prefixed = raw.WithKeyPrefix(""); var prefixed = raw.WithKeyPrefix("");
Assert.AreSame(raw, prefixed); Assert.AreSame(raw, prefixed);
} }
} }
[Test, ExpectedException(typeof(ArgumentNullException))] [Test]
public void NullPrefixIsError_Bytes() public void NullPrefixIsError_Bytes()
{ {
using (var conn = Create()) Assert.Throws<ArgumentNullException>(() => {
{ using (var conn = Create())
var raw = conn.GetDatabase(1); {
var prefixed = raw.WithKeyPrefix((byte[])null); var raw = conn.GetDatabase(1);
} var prefixed = raw.WithKeyPrefix((byte[])null);
} }
[Test, ExpectedException(typeof(ArgumentNullException))] });
public void NullPrefixIsError_String() }
{
using (var conn = Create()) [Test]
{ public void NullPrefixIsError_String()
var raw = conn.GetDatabase(1); {
var prefixed = raw.WithKeyPrefix((string)null); Assert.Throws<ArgumentNullException>(() => {
} using (var conn = Create())
} {
var raw = conn.GetDatabase(1);
[Test, ExpectedException(typeof(ArgumentNullException))] var prefixed = raw.WithKeyPrefix((string)null);
[TestCase("abc")] }
[TestCase("")] });
[TestCase(null)] }
public void NullDatabaseIsError(string prefix)
{ [Test]
IDatabase raw = null; [TestCase("abc")]
var prefixed = raw.WithKeyPrefix(prefix); [TestCase("")]
} [TestCase(null)]
[Test] public void NullDatabaseIsError(string prefix)
public void BasicSmokeTest() {
{ Assert.Throws<ArgumentNullException>(() => {
using(var conn = Create()) IDatabase raw = null;
{ var prefixed = raw.WithKeyPrefix(prefix);
var raw = conn.GetDatabase(1); });
}
var foo = raw.WithKeyPrefix("foo");
var foobar = foo.WithKeyPrefix("bar"); [Test]
public void BasicSmokeTest()
string key = Me(); {
using(var conn = Create())
string s = Guid.NewGuid().ToString(), t = Guid.NewGuid().ToString(); {
var raw = conn.GetDatabase(1);
foo.StringSet(key, s);
var val = (string)foo.StringGet(key); var foo = raw.WithKeyPrefix("foo");
Assert.AreEqual(s, val); // fooBasicSmokeTest var foobar = foo.WithKeyPrefix("bar");
foobar.StringSet(key, t); string key = Me();
val = (string)foobar.StringGet(key);
Assert.AreEqual(t, val); // foobarBasicSmokeTest string s = Guid.NewGuid().ToString(), t = Guid.NewGuid().ToString();
val = (string)foo.StringGet("bar" + key); foo.StringSet(key, s);
Assert.AreEqual(t, val); // foobarBasicSmokeTest var val = (string)foo.StringGet(key);
Assert.AreEqual(s, val); // fooBasicSmokeTest
val = (string)raw.StringGet("foo" + key);
Assert.AreEqual(s, val); // fooBasicSmokeTest foobar.StringSet(key, t);
val = (string)foobar.StringGet(key);
val = (string)raw.StringGet("foobar" + key); Assert.AreEqual(t, val); // foobarBasicSmokeTest
Assert.AreEqual(t, val); // foobarBasicSmokeTest
} val = (string)foo.StringGet("bar" + key);
} Assert.AreEqual(t, val); // foobarBasicSmokeTest
[Test]
public void ConditionTest() val = (string)raw.StringGet("foo" + key);
{ Assert.AreEqual(s, val); // fooBasicSmokeTest
using(var conn = Create())
{ val = (string)raw.StringGet("foobar" + key);
var raw = conn.GetDatabase(2); Assert.AreEqual(t, val); // foobarBasicSmokeTest
}
var foo = raw.WithKeyPrefix("tran:"); }
[Test]
raw.KeyDelete("tran:abc"); public void ConditionTest()
raw.KeyDelete("tran:i"); {
using(var conn = Create())
// execute while key exists {
raw.StringSet("tran:abc", "def"); var raw = conn.GetDatabase(2);
var tran = foo.CreateTransaction();
tran.AddCondition(Condition.KeyExists("abc")); var foo = raw.WithKeyPrefix("tran:");
tran.StringIncrementAsync("i");
tran.Execute(); raw.KeyDelete("tran:abc");
raw.KeyDelete("tran:i");
int i = (int)raw.StringGet("tran:i");
Assert.AreEqual(1, i); // execute while key exists
raw.StringSet("tran:abc", "def");
// repeat without key var tran = foo.CreateTransaction();
raw.KeyDelete("tran:abc"); tran.AddCondition(Condition.KeyExists("abc"));
tran = foo.CreateTransaction(); tran.StringIncrementAsync("i");
tran.AddCondition(Condition.KeyExists("abc")); tran.Execute();
tran.StringIncrementAsync("i");
tran.Execute(); int i = (int)raw.StringGet("tran:i");
Assert.AreEqual(1, i);
i = (int)raw.StringGet("tran:i");
Assert.AreEqual(1, i); // repeat without key
} raw.KeyDelete("tran:abc");
} tran = foo.CreateTransaction();
} tran.AddCondition(Condition.KeyExists("abc"));
} tran.StringIncrementAsync("i");
tran.Execute();
i = (int)raw.StringGet("tran:i");
Assert.AreEqual(1, i);
}
}
}
}
using System; #if FEATURE_MOQ
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq.Expressions; using System.Linq.Expressions;
using System.Net; using System.Net;
...@@ -15,7 +16,8 @@ public sealed class WrapperBaseTests ...@@ -15,7 +16,8 @@ public sealed class WrapperBaseTests
private Mock<IDatabaseAsync> mock; private Mock<IDatabaseAsync> mock;
private WrapperBase<IDatabaseAsync> wrapper; private WrapperBase<IDatabaseAsync> wrapper;
[TestFixtureSetUp] //[TestFixtureSetUp]
[OneTimeSetUp]
public void Initialize() public void Initialize()
{ {
mock = new Mock<IDatabaseAsync>(); mock = new Mock<IDatabaseAsync>();
...@@ -258,10 +260,11 @@ public void KeyPersistAsync() ...@@ -258,10 +260,11 @@ public void KeyPersistAsync()
} }
[Test] [Test]
[ExpectedException(typeof(NotSupportedException))]
public void KeyRandomAsync() public void KeyRandomAsync()
{ {
wrapper.KeyRandomAsync(); Assert.Throws<NotSupportedException>(() => {
wrapper.KeyRandomAsync();
});
} }
[Test] [Test]
...@@ -888,3 +891,4 @@ public void StringSetRangeAsync() ...@@ -888,3 +891,4 @@ public void StringSetRangeAsync()
} }
} }
} }
#endif
\ No newline at end of file
...@@ -2,5 +2,5 @@ ...@@ -2,5 +2,5 @@
<packages> <packages>
<package id="BookSleeve" version="1.3.41" targetFramework="net45" /> <package id="BookSleeve" version="1.3.41" targetFramework="net45" />
<package id="Moq" version="4.2.1502.0911" targetFramework="net45" /> <package id="Moq" version="4.2.1502.0911" targetFramework="net45" />
<package id="NUnit" version="2.6.4" targetFramework="net45" /> <package id="NUnit" version="3.0.0" targetFramework="net45" />
</packages> </packages>
\ No newline at end of file
using System;
using System.Reflection;
using NUnitLite;
namespace StackExchange.Redis.Tests
{
public class Program
{
public int Main(string[] args)
{
return new AutoRun().Execute(typeof(TestBase).GetTypeInfo().Assembly, Console.Out, Console.In, args);
}
}
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>a51dca17-e8f1-44e1-9a37-328fab14d2ce</ProjectGuid>
<RootNamespace>StackExchange.Redis.Tests</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\StackExchange.Redis_dnxcore50\StackExchange.Redis\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\StackExchange.Redis_dnxcore50\StackExchange.Redis\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>
\ No newline at end of file
{
"version": "1.0.0-*",
"description": "StackExchange.Redis.Tests",
"authors": [ "jeremymeng" ],
"tags": [ "" ],
"projectUrl": "",
"licenseUrl": "",
"compile": [
"../../StackExchange.Redis.Tests/**/*.cs"
],
"dependencies": {
"StackExchange.Redis": "1.1.0-*"
},
"commands": {
"run": "StackExchange.Redis.Tests"
},
"configurations": {
"Debug": {
"compilationOptions": {
"define": [ "DEBUG", "TRACE", "PLAT_SAFE_CONTINUATIONS" ]
}
},
"Release": {
"compilationOptions": {
"define": [ "TRACE", "PLAT_SAFE_CONTINUATIONS" ]
}
}
},
"frameworks": {
"dnxcore50": {
"dependencies": {
"System.Console": "4.0.0-beta-*",
"System.Linq.Expressions": "4.0.11-beta-23409",
"System.Reflection.Extensions": "4.0.1-beta-23409",
"System.Threading.Tasks.Parallel": "4.0.1-beta-23409",
"Microsoft.CSharp": "4.0.1-beta-23409",
"nunitlite": "3.0.0"
}
}
}
}

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.24709.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "StackExchange.Redis", "StackExchange.Redis_dnxcore50\StackExchange.Redis\StackExchange.Redis.xproj", "{86526B5C-1163-4481-A5E2-A303A0BB1535}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "StackExchange.Redis.Tests", "StackExchange.Redis.Tests_dnxcore50\StackExchange.Redis.Tests\StackExchange.Redis.Tests.xproj", "{A51DCA17-E8F1-44E1-9A37-328FAB14D2CE}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "BasicTest_dnxcore50", "BasicTest_dnxcore50\BasicTest_dnxcore50.xproj", "{9D83BABA-A92E-495F-BF63-DEB4F6B09355}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{86526B5C-1163-4481-A5E2-A303A0BB1535}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{86526B5C-1163-4481-A5E2-A303A0BB1535}.Debug|Any CPU.Build.0 = Debug|Any CPU
{86526B5C-1163-4481-A5E2-A303A0BB1535}.Release|Any CPU.ActiveCfg = Release|Any CPU
{86526B5C-1163-4481-A5E2-A303A0BB1535}.Release|Any CPU.Build.0 = Release|Any CPU
{A51DCA17-E8F1-44E1-9A37-328FAB14D2CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A51DCA17-E8F1-44E1-9A37-328FAB14D2CE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A51DCA17-E8F1-44E1-9A37-328FAB14D2CE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A51DCA17-E8F1-44E1-9A37-328FAB14D2CE}.Release|Any CPU.Build.0 = Release|Any CPU
{9D83BABA-A92E-495F-BF63-DEB4F6B09355}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9D83BABA-A92E-495F-BF63-DEB4F6B09355}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9D83BABA-A92E-495F-BF63-DEB4F6B09355}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9D83BABA-A92E-495F-BF63-DEB4F6B09355}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
<DebugType>full</DebugType> <DebugType>full</DebugType>
<Optimize>false</Optimize> <Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath> <OutputPath>bin\Debug\</OutputPath>
<DefineConstants>TRACE;DEBUG</DefineConstants> <DefineConstants>TRACE;DEBUG;FEATURE_SERIALIZATION FEATURE_SOCKET_MODE_POLL</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
<DebugType>pdbonly</DebugType> <DebugType>pdbonly</DebugType>
<Optimize>true</Optimize> <Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath> <OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants> <DefineConstants>TRACE;FEATURE_SERIALIZATION FEATURE_SOCKET_MODE_POLL</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Verbose|AnyCPU'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Verbose|AnyCPU'">
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>
<OutputPath>bin\Verbose\</OutputPath> <OutputPath>bin\Verbose\</OutputPath>
<DefineConstants>TRACE;DEBUG;VERBOSE</DefineConstants> <DefineConstants>TRACE;DEBUG;VERBOSE;FEATURE_SERIALIZATION FEATURE_SOCKET_MODE_POLL</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DocumentationFile>bin\Debug\StackExchange.Redis.xml</DocumentationFile> <DocumentationFile>bin\Debug\StackExchange.Redis.xml</DocumentationFile>
<DebugType>full</DebugType> <DebugType>full</DebugType>
...@@ -48,7 +48,7 @@ ...@@ -48,7 +48,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Log Output|AnyCPU'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Log Output|AnyCPU'">
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>
<OutputPath>bin\Log Output\</OutputPath> <OutputPath>bin\Log Output\</OutputPath>
<DefineConstants>TRACE;DEBUG;LOGOUTPUT</DefineConstants> <DefineConstants>TRACE;DEBUG;LOGOUTPUT FEATURE_SERIALIZATION FEATURE_SOCKET_MODE_POLL</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DocumentationFile>bin\Debug\StackExchange.Redis.xml</DocumentationFile> <DocumentationFile>bin\Debug\StackExchange.Redis.xml</DocumentationFile>
<DebugType>full</DebugType> <DebugType>full</DebugType>
...@@ -58,7 +58,7 @@ ...@@ -58,7 +58,7 @@
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Mono|AnyCPU'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Mono|AnyCPU'">
<OutputPath>bin\Mono\</OutputPath> <OutputPath>bin\Mono\</OutputPath>
<DefineConstants>TRACE;__MonoCS__</DefineConstants> <DefineConstants>TRACE;__MonoCS__ FEATURE_SERIALIZATION</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DocumentationFile>bin\Release\StackExchange.Redis.xml</DocumentationFile> <DocumentationFile>bin\Release\StackExchange.Redis.xml</DocumentationFile>
<Optimize>true</Optimize> <Optimize>true</Optimize>
...@@ -75,6 +75,7 @@ ...@@ -75,6 +75,7 @@
<ItemGroup> <ItemGroup>
<Compile Include="StackExchange\Redis\Aggregate.cs" /> <Compile Include="StackExchange\Redis\Aggregate.cs" />
<Compile Include="StackExchange\Redis\ClientType.cs" /> <Compile Include="StackExchange\Redis\ClientType.cs" />
<Compile Include="StackExchange\Redis\Compat\VolatileWrapper.cs" />
<Compile Include="StackExchange\Redis\ConcurrentProfileStorageCollection.cs" /> <Compile Include="StackExchange\Redis\ConcurrentProfileStorageCollection.cs" />
<Compile Include="StackExchange\Redis\ConnectionMultiplexer.Profiling.cs"> <Compile Include="StackExchange\Redis\ConnectionMultiplexer.Profiling.cs">
<DependentUpon>ConnectionMultiplexer.cs</DependentUpon> <DependentUpon>ConnectionMultiplexer.cs</DependentUpon>
...@@ -83,6 +84,7 @@ ...@@ -83,6 +84,7 @@
<Compile Include="StackExchange\Redis\HashEntry.cs" /> <Compile Include="StackExchange\Redis\HashEntry.cs" />
<Compile Include="StackExchange\Redis\IConnectionMultiplexer.cs" /> <Compile Include="StackExchange\Redis\IConnectionMultiplexer.cs" />
<Compile Include="StackExchange\Redis\InternalErrorEventArgs.cs" /> <Compile Include="StackExchange\Redis\InternalErrorEventArgs.cs" />
<Compile Include="StackExchange\Redis\InternalRegexCompiledOption.cs" />
<Compile Include="StackExchange\Redis\IProfiler.cs" /> <Compile Include="StackExchange\Redis\IProfiler.cs" />
<Compile Include="StackExchange\Redis\MigrateOptions.cs" /> <Compile Include="StackExchange\Redis\MigrateOptions.cs" />
<Compile Include="StackExchange\Redis\ProfileContextTracker.cs" /> <Compile Include="StackExchange\Redis\ProfileContextTracker.cs" />
......
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace StackExchange.Redis
{
internal static class VolatileWrapper
{
public static int Read(ref int location)
{
#if !DNXCORE50
return System.Threading.Thread.VolatileRead(ref location);
#else
return System.Threading.Volatile.Read(ref location);
#endif
}
public static void Write(ref int address, int value)
{
#if !DNXCORE50
System.Threading.Thread.VolatileWrite(ref address, value);
#else
System.Threading.Volatile.Write(ref address, value);
#endif
}
}
}
...@@ -145,7 +145,7 @@ private void ProcessAsyncCompletionQueueImpl() ...@@ -145,7 +145,7 @@ private void ProcessAsyncCompletionQueueImpl()
// give it a moment and try again, noting that we might lose the battle // give it a moment and try again, noting that we might lose the battle
// when we pause // when we pause
Interlocked.CompareExchange(ref activeAsyncWorkerThread, 0, currentThread); Interlocked.CompareExchange(ref activeAsyncWorkerThread, 0, currentThread);
if (Thread.Yield() && Interlocked.CompareExchange(ref activeAsyncWorkerThread, currentThread, 0) == 0) if (SpinWait() && Interlocked.CompareExchange(ref activeAsyncWorkerThread, currentThread, 0) == 0)
{ {
// we paused, and we got the lock back; anything else? // we paused, and we got the lock back; anything else?
lock (asyncCompletionQueue) lock (asyncCompletionQueue)
...@@ -176,5 +176,20 @@ private void ProcessAsyncCompletionQueueImpl() ...@@ -176,5 +176,20 @@ private void ProcessAsyncCompletionQueueImpl()
Interlocked.CompareExchange(ref activeAsyncWorkerThread, 0, currentThread); Interlocked.CompareExchange(ref activeAsyncWorkerThread, 0, currentThread);
} }
} }
private bool SpinWait()
{
var sw = new SpinWait();
byte maxSpins = 128;
do
{
if (sw.NextSpinWillYield)
return true;
maxSpins--;
}
while (maxSpins > 0);
return false;
}
} }
} }
...@@ -29,7 +29,10 @@ public enum Proxy ...@@ -29,7 +29,10 @@ public enum Proxy
/// <summary> /// <summary>
/// The options relevant to a set of redis connections /// The options relevant to a set of redis connections
/// </summary> /// </summary>
public sealed class ConfigurationOptions : ICloneable public sealed class ConfigurationOptions
#if !DNXCORE50
: ICloneable
#endif
{ {
internal const string DefaultTieBreaker = "__Booksleeve_TieBreak", DefaultConfigurationChannel = "__Booksleeve_MasterChanged"; internal const string DefaultTieBreaker = "__Booksleeve_TieBreak", DefaultConfigurationChannel = "__Booksleeve_MasterChanged";
...@@ -84,7 +87,7 @@ internal static void Unknown(string key) ...@@ -84,7 +87,7 @@ internal static void Unknown(string key)
ConfigChannel, AbortOnConnectFail, ResolveDns, ConfigChannel, AbortOnConnectFail, ResolveDns,
ChannelPrefix, Proxy, ConnectRetry, ChannelPrefix, Proxy, ConnectRetry,
ConfigCheckSeconds, DefaultDatabase, ConfigCheckSeconds, DefaultDatabase,
}.ToDictionary(x => x, StringComparer.InvariantCultureIgnoreCase); }.ToDictionary(x => x, StringComparer.OrdinalIgnoreCase);
public static string TryNormalize(string value) public static string TryNormalize(string value)
{ {
...@@ -139,7 +142,11 @@ public static string TryNormalize(string value) ...@@ -139,7 +142,11 @@ public static string TryNormalize(string value)
/// <summary> /// <summary>
/// Indicates whether the connection should be encrypted /// Indicates whether the connection should be encrypted
/// </summary> /// </summary>
[Obsolete("Please use .Ssl instead of .UseSsl"), Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] [Obsolete("Please use .Ssl instead of .UseSsl"),
#if !DNXCORE50
Browsable(false),
#endif
EditorBrowsable(EditorBrowsableState.Never)]
public bool UseSsl { get { return Ssl; } set { Ssl = value; } } public bool UseSsl { get { return Ssl; } set { Ssl = value; } }
/// <summary> /// <summary>
...@@ -248,7 +255,7 @@ public CommandMap CommandMap ...@@ -248,7 +255,7 @@ public CommandMap CommandMap
/// <summary> /// <summary>
/// Specifies the time in milliseconds that the system should allow for synchronous operations (defaults to 1 second) /// Specifies the time in milliseconds that the system should allow for synchronous operations (defaults to 1 second)
/// </summary> /// </summary>
public int SyncTimeout { get { return syncTimeout.GetValueOrDefault(1000); } set { syncTimeout = value; } } public int SyncTimeout { get { return syncTimeout.GetValueOrDefault(20000); } set { syncTimeout = value; } }
/// <summary> /// <summary>
/// Specifies the time in milliseconds that the system should allow for responses before concluding that the socket is unhealthy /// Specifies the time in milliseconds that the system should allow for responses before concluding that the socket is unhealthy
...@@ -394,7 +401,7 @@ internal bool HasDnsEndPoints() ...@@ -394,7 +401,7 @@ internal bool HasDnsEndPoints()
#pragma warning disable 1998 // NET40 is sync, not async, currently #pragma warning disable 1998 // NET40 is sync, not async, currently
internal async Task ResolveEndPointsAsync(ConnectionMultiplexer multiplexer, TextWriter log) internal async Task ResolveEndPointsAsync(ConnectionMultiplexer multiplexer, TextWriter log)
{ {
Dictionary<string, IPAddress> cache = new Dictionary<string, IPAddress>(StringComparer.InvariantCultureIgnoreCase); Dictionary<string, IPAddress> cache = new Dictionary<string, IPAddress>(StringComparer.OrdinalIgnoreCase);
for (int i = 0; i < endpoints.Count; i++) for (int i = 0; i < endpoints.Count; i++)
{ {
var dns = endpoints[i] as DnsEndPoint; var dns = endpoints[i] as DnsEndPoint;
...@@ -463,10 +470,13 @@ static void Append(StringBuilder sb, string prefix, object value) ...@@ -463,10 +470,13 @@ static void Append(StringBuilder sb, string prefix, object value)
} }
} }
#if !DNXCORE50
static bool IsOption(string option, string prefix) static bool IsOption(string option, string prefix)
{ {
return option.StartsWith(prefix, StringComparison.InvariantCultureIgnoreCase); return option.StartsWith(prefix, StringComparison.InvariantCultureIgnoreCase);
} }
#endif
void Clear() void Clear()
{ {
clientName = serviceName = password = tieBreaker = sslHost = configChannel = null; clientName = serviceName = password = tieBreaker = sslHost = configChannel = null;
...@@ -482,7 +492,9 @@ void Clear() ...@@ -482,7 +492,9 @@ void Clear()
SocketManager = null; SocketManager = null;
} }
#if !DNXCORE50
object ICloneable.Clone() { return Clone(); } object ICloneable.Clone() { return Clone(); }
#endif
private void DoParse(string configuration, bool ignoreUnknown) private void DoParse(string configuration, bool ignoreUnknown)
{ {
...@@ -586,7 +598,7 @@ private void DoParse(string configuration, bool ignoreUnknown) ...@@ -586,7 +598,7 @@ private void DoParse(string configuration, bool ignoreUnknown)
var cmdName = option.Substring(1, idx - 1); var cmdName = option.Substring(1, idx - 1);
if (Enum.TryParse(cmdName, true, out cmd)) if (Enum.TryParse(cmdName, true, out cmd))
{ {
if (map == null) map = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase); if (map == null) map = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
map[cmdName] = value; map[cmdName] = value;
} }
} }
......
...@@ -95,7 +95,7 @@ public ServerCounters GetCounters() ...@@ -95,7 +95,7 @@ public ServerCounters GetCounters()
/// <summary> /// <summary>
/// Gets the client-name that will be used on all new connections /// Gets the client-name that will be used on all new connections
/// </summary> /// </summary>
public string ClientName { get { return configuration.ClientName ?? Environment.MachineName; } } public string ClientName { get { return configuration.ClientName ?? Environment.GetEnvironmentVariable("ComputerName"); } }
/// <summary> /// <summary>
/// Gets the configuration of the connection /// Gets the configuration of the connection
...@@ -482,7 +482,7 @@ public EndPoint[] GetEndPoints(bool configuredOnly = false) ...@@ -482,7 +482,7 @@ public EndPoint[] GetEndPoints(bool configuredOnly = false)
{ {
if (configuredOnly) return configuration.EndPoints.ToArray(); if (configuredOnly) return configuration.EndPoints.ToArray();
return Array.ConvertAll(serverSnapshot, x => x.EndPoint); return serverSnapshot.Select(x => x.EndPoint).ToArray();
} }
private readonly int timeoutMilliseconds; private readonly int timeoutMilliseconds;
...@@ -560,6 +560,8 @@ private static bool WaitAllIgnoreErrors(Task[] tasks, int timeout) ...@@ -560,6 +560,8 @@ private static bool WaitAllIgnoreErrors(Task[] tasks, int timeout)
} }
return false; return false;
} }
#if !DNXCORE50
private void LogLockedWithThreadPoolStats(TextWriter log, string message, out int busyWorkerCount) private void LogLockedWithThreadPoolStats(TextWriter log, string message, out int busyWorkerCount)
{ {
busyWorkerCount = 0; busyWorkerCount = 0;
...@@ -573,6 +575,8 @@ private void LogLockedWithThreadPoolStats(TextWriter log, string message, out in ...@@ -573,6 +575,8 @@ private void LogLockedWithThreadPoolStats(TextWriter log, string message, out in
LogLocked(log, sb.ToString()); LogLocked(log, sb.ToString());
} }
} }
#endif
static bool AllComplete(Task[] tasks) static bool AllComplete(Task[] tasks)
{ {
for(int i = 0 ; i < tasks.Length ; i++) for(int i = 0 ; i < tasks.Length ; i++)
...@@ -599,16 +603,19 @@ private async Task<bool> WaitAllIgnoreErrorsAsync(Task[] tasks, int timeoutMilli ...@@ -599,16 +603,19 @@ private async Task<bool> WaitAllIgnoreErrorsAsync(Task[] tasks, int timeoutMilli
} }
var watch = Stopwatch.StartNew(); var watch = Stopwatch.StartNew();
#if !DNXCORE50
int busyWorkerCount; int busyWorkerCount;
LogLockedWithThreadPoolStats(log, "Awaiting task completion", out busyWorkerCount); LogLockedWithThreadPoolStats(log, "Awaiting task completion", out busyWorkerCount);
#endif
try try
{ {
// if none error, great // if none error, great
var remaining = timeoutMilliseconds - checked((int)watch.ElapsedMilliseconds); var remaining = timeoutMilliseconds - checked((int)watch.ElapsedMilliseconds);
if (remaining <= 0) if (remaining <= 0)
{ {
#if !DNXCORE50
LogLockedWithThreadPoolStats(log, "Timeout before awaiting for tasks", out busyWorkerCount); LogLockedWithThreadPoolStats(log, "Timeout before awaiting for tasks", out busyWorkerCount);
#endif
return false; return false;
} }
...@@ -620,7 +627,9 @@ private async Task<bool> WaitAllIgnoreErrorsAsync(Task[] tasks, int timeoutMilli ...@@ -620,7 +627,9 @@ private async Task<bool> WaitAllIgnoreErrorsAsync(Task[] tasks, int timeoutMilli
var any = Task.WhenAny(allTasks, Task.Delay(remaining)).ObserveErrors(); var any = Task.WhenAny(allTasks, Task.Delay(remaining)).ObserveErrors();
#endif #endif
bool all = await any.ForAwait() == allTasks; bool all = await any.ForAwait() == allTasks;
#if !DNXCORE50
LogLockedWithThreadPoolStats(log, all ? "All tasks completed cleanly" : "Not all tasks completed cleanly", out busyWorkerCount); LogLockedWithThreadPoolStats(log, all ? "All tasks completed cleanly" : "Not all tasks completed cleanly", out busyWorkerCount);
#endif
return all; return all;
} }
catch catch
...@@ -636,7 +645,9 @@ private async Task<bool> WaitAllIgnoreErrorsAsync(Task[] tasks, int timeoutMilli ...@@ -636,7 +645,9 @@ private async Task<bool> WaitAllIgnoreErrorsAsync(Task[] tasks, int timeoutMilli
var remaining = timeoutMilliseconds - checked((int)watch.ElapsedMilliseconds); var remaining = timeoutMilliseconds - checked((int)watch.ElapsedMilliseconds);
if (remaining <= 0) if (remaining <= 0)
{ {
#if !DNXCORE50
LogLockedWithThreadPoolStats(log, "Timeout awaiting tasks", out busyWorkerCount); LogLockedWithThreadPoolStats(log, "Timeout awaiting tasks", out busyWorkerCount);
#endif
return false; return false;
} }
try try
...@@ -652,7 +663,9 @@ private async Task<bool> WaitAllIgnoreErrorsAsync(Task[] tasks, int timeoutMilli ...@@ -652,7 +663,9 @@ private async Task<bool> WaitAllIgnoreErrorsAsync(Task[] tasks, int timeoutMilli
{ } { }
} }
} }
#if !DNXCORE50
LogLockedWithThreadPoolStats(log, "Finished awaiting tasks", out busyWorkerCount); LogLockedWithThreadPoolStats(log, "Finished awaiting tasks", out busyWorkerCount);
#endif
return false; return false;
} }
...@@ -927,12 +940,12 @@ private void OnHeartbeat() ...@@ -927,12 +940,12 @@ private void OnHeartbeat()
private static int lastGlobalHeartbeatTicks = Environment.TickCount; private static int lastGlobalHeartbeatTicks = Environment.TickCount;
internal long LastHeartbeatSecondsAgo { internal long LastHeartbeatSecondsAgo {
get { get {
if (pulse == null) return -1; if (pulse == null) return -1;
return unchecked(Environment.TickCount - Thread.VolatileRead(ref lastHeartbeatTicks)) / 1000; return unchecked(Environment.TickCount - VolatileWrapper.Read(ref lastHeartbeatTicks)) / 1000;
} }
} }
internal static long LastGlobalHeartbeatSecondsAgo internal static long LastGlobalHeartbeatSecondsAgo
{ get { return unchecked(Environment.TickCount - Thread.VolatileRead(ref lastGlobalHeartbeatTicks)) / 1000; } } { get { return unchecked(Environment.TickCount - VolatileWrapper.Read(ref lastGlobalHeartbeatTicks)) / 1000; } }
internal CompletionManager UnprocessableCompletionManager { get { return unprocessableCompletionManager; } } internal CompletionManager UnprocessableCompletionManager { get { return unprocessableCompletionManager; } }
...@@ -1434,7 +1447,7 @@ private async Task<ServerEndPoint> NominatePreferredMaster(TextWriter log, Serve ...@@ -1434,7 +1447,7 @@ private async Task<ServerEndPoint> NominatePreferredMaster(TextWriter log, Serve
Dictionary<string, int> uniques = null; Dictionary<string, int> uniques = null;
if (useTieBreakers) if (useTieBreakers)
{ // count the votes { // count the votes
uniques = new Dictionary<string, int>(StringComparer.InvariantCultureIgnoreCase); uniques = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
await WaitAllIgnoreErrorsAsync(tieBreakers, 50, log).ForAwait(); await WaitAllIgnoreErrorsAsync(tieBreakers, 50, log).ForAwait();
for (int i = 0; i < tieBreakers.Length; i++) for (int i = 0; i < tieBreakers.Length; i++)
{ {
...@@ -1874,8 +1887,7 @@ internal T ExecuteSyncImpl<T>(Message message, ResultProcessor<T> processor, Ser ...@@ -1874,8 +1887,7 @@ internal T ExecuteSyncImpl<T>(Message message, ResultProcessor<T> processor, Ser
else else
{ {
int inst, qu, qs, qc, wr, wq, @in, ar; int inst, qu, qs, qc, wr, wq, @in, ar;
string iocp, worker; #if FEATURE_SOCKET_MODE_POLL
#if !__MonoCS__
var mgrState = socketManager.State; var mgrState = socketManager.State;
var lastError = socketManager.LastErrorTimeRelative(); var lastError = socketManager.LastErrorTimeRelative();
...@@ -1889,9 +1901,8 @@ internal T ExecuteSyncImpl<T>(Message message, ResultProcessor<T> processor, Ser ...@@ -1889,9 +1901,8 @@ internal T ExecuteSyncImpl<T>(Message message, ResultProcessor<T> processor, Ser
}; };
int queue = server.GetOutstandingCount(message.Command, out inst, out qu, out qs, out qc, out wr, out wq, out @in, out ar); int queue = server.GetOutstandingCount(message.Command, out inst, out qu, out qs, out qc, out wr, out wq, out @in, out ar);
int busyWorkerCount = GetThreadPoolStats(out iocp, out worker);
add("Instantaneous", "inst", inst.ToString()); add("Instantaneous", "inst", inst.ToString());
#if !__MonoCS__ #if FEATURE_SOCKET_MODE_POLL
add("Manager-State", "mgr", mgrState.ToString()); add("Manager-State", "mgr", mgrState.ToString());
add("Last-Error", "err", lastError); add("Last-Error", "err", lastError);
#endif #endif
...@@ -1904,10 +1915,14 @@ internal T ExecuteSyncImpl<T>(Message message, ResultProcessor<T> processor, Ser ...@@ -1904,10 +1915,14 @@ internal T ExecuteSyncImpl<T>(Message message, ResultProcessor<T> processor, Ser
add("Inbound-Bytes", "in", @in.ToString()); add("Inbound-Bytes", "in", @in.ToString());
add("Active-Readers", "ar", ar.ToString()); add("Active-Readers", "ar", ar.ToString());
add("Client-Name", "clientName", ClientName);
#if !DNXCORE50
string iocp, worker;
int busyWorkerCount = GetThreadPoolStats(out iocp, out worker);
add("ThreadPool-IO-Completion", "IOCP", iocp); add("ThreadPool-IO-Completion", "IOCP", iocp);
add("ThreadPool-Workers", "WORKER", worker); add("ThreadPool-Workers", "WORKER", worker);
add("Client-Name", "clientName", ClientName);
data.Add(Tuple.Create("Busy-Workers", busyWorkerCount.ToString())); data.Add(Tuple.Create("Busy-Workers", busyWorkerCount.ToString()));
#endif
errMessage = sb.ToString(); errMessage = sb.ToString();
if (stormLogThreshold >= 0 && queue >= stormLogThreshold && Interlocked.CompareExchange(ref haveStormLog, 1, 0) == 0) if (stormLogThreshold >= 0 && queue >= stormLogThreshold && Interlocked.CompareExchange(ref haveStormLog, 1, 0) == 0)
{ {
...@@ -1936,7 +1951,9 @@ internal T ExecuteSyncImpl<T>(Message message, ResultProcessor<T> processor, Ser ...@@ -1936,7 +1951,9 @@ internal T ExecuteSyncImpl<T>(Message message, ResultProcessor<T> processor, Ser
Trace(message + " received " + val); Trace(message + " received " + val);
return val; return val;
} }
} }
#if !DNXCORE50
private static int GetThreadPoolStats(out string iocp, out string worker) private static int GetThreadPoolStats(out string iocp, out string worker)
{ {
//BusyThreads = TP.GetMaxThreads() –TP.GetAVailable(); //BusyThreads = TP.GetMaxThreads() –TP.GetAVailable();
...@@ -1958,6 +1975,7 @@ private static int GetThreadPoolStats(out string iocp, out string worker) ...@@ -1958,6 +1975,7 @@ private static int GetThreadPoolStats(out string iocp, out string worker)
worker = string.Format("(Busy={0},Free={1},Min={2},Max={3})", busyWorkerThreads, freeWorkerThreads, minWorkerThreads, maxWorkerThreads); worker = string.Format("(Busy={0},Free={1},Min={2},Max={3})", busyWorkerThreads, freeWorkerThreads, minWorkerThreads, maxWorkerThreads);
return busyWorkerThreads; return busyWorkerThreads;
} }
#endif
/// <summary> /// <summary>
/// Should exceptions include identifiable details? (key names, additional .Data annotations) /// Should exceptions include identifiable details? (key names, additional .Data annotations)
......
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
namespace StackExchange.Redis
{ namespace StackExchange.Redis
/// <summary> {
/// Utility methods /// <summary>
/// </summary> /// Utility methods
public static class ExtensionMethods /// </summary>
{ public static class ExtensionMethods
/// <summary> {
/// Create a dictionary from an array of HashEntry values /// <summary>
/// </summary> /// Create a dictionary from an array of HashEntry values
public static Dictionary<string,string> ToStringDictionary(this HashEntry[] hash) /// </summary>
{ public static Dictionary<string,string> ToStringDictionary(this HashEntry[] hash)
if (hash == null) return null; {
if (hash == null) return null;
var result = new Dictionary<string, string>(hash.Length, StringComparer.Ordinal);
for(int i = 0; i < hash.Length; i++) var result = new Dictionary<string, string>(hash.Length, StringComparer.Ordinal);
{ for(int i = 0; i < hash.Length; i++)
result.Add(hash[i].name, hash[i].value); {
} result.Add(hash[i].name, hash[i].value);
return result; }
} return result;
/// <summary> }
/// Create a dictionary from an array of HashEntry values /// <summary>
/// </summary> /// Create a dictionary from an array of HashEntry values
public static Dictionary<RedisValue, RedisValue> ToDictionary(this HashEntry[] hash) /// </summary>
{ public static Dictionary<RedisValue, RedisValue> ToDictionary(this HashEntry[] hash)
if (hash == null) return null; {
if (hash == null) return null;
var result = new Dictionary<RedisValue, RedisValue>(hash.Length);
for (int i = 0; i < hash.Length; i++) var result = new Dictionary<RedisValue, RedisValue>(hash.Length);
{ for (int i = 0; i < hash.Length; i++)
result.Add(hash[i].name, hash[i].value); {
} result.Add(hash[i].name, hash[i].value);
return result; }
} return result;
}
/// <summary>
/// Create a dictionary from an array of SortedSetEntry values /// <summary>
/// </summary> /// Create a dictionary from an array of SortedSetEntry values
public static Dictionary<string, double> ToStringDictionary(this SortedSetEntry[] sortedSet) /// </summary>
{ public static Dictionary<string, double> ToStringDictionary(this SortedSetEntry[] sortedSet)
if (sortedSet == null) return null; {
if (sortedSet == null) return null;
var result = new Dictionary<string, double>(sortedSet.Length, StringComparer.Ordinal);
for (int i = 0; i < sortedSet.Length; i++) var result = new Dictionary<string, double>(sortedSet.Length, StringComparer.Ordinal);
{ for (int i = 0; i < sortedSet.Length; i++)
result.Add(sortedSet[i].element, sortedSet[i].score); {
} result.Add(sortedSet[i].element, sortedSet[i].score);
return result; }
} return result;
}
/// <summary>
/// Create a dictionary from an array of SortedSetEntry values /// <summary>
/// </summary> /// Create a dictionary from an array of SortedSetEntry values
public static Dictionary<RedisValue, double> ToDictionary(this SortedSetEntry[] sortedSet) /// </summary>
{ public static Dictionary<RedisValue, double> ToDictionary(this SortedSetEntry[] sortedSet)
if (sortedSet == null) return null; {
if (sortedSet == null) return null;
var result = new Dictionary<RedisValue, double>(sortedSet.Length);
for (int i = 0; i < sortedSet.Length; i++) var result = new Dictionary<RedisValue, double>(sortedSet.Length);
{ for (int i = 0; i < sortedSet.Length; i++)
result.Add(sortedSet[i].element, sortedSet[i].score); {
} result.Add(sortedSet[i].element, sortedSet[i].score);
return result; }
} return result;
}
/// <summary>
/// Create a dictionary from an array of key/value pairs /// <summary>
/// </summary> /// Create a dictionary from an array of key/value pairs
public static Dictionary<string, string> ToStringDictionary(this KeyValuePair<RedisKey, RedisValue>[] pairs) /// </summary>
{ public static Dictionary<string, string> ToStringDictionary(this KeyValuePair<RedisKey, RedisValue>[] pairs)
if (pairs == null) return null; {
if (pairs == null) return null;
var result = new Dictionary<string, string>(pairs.Length, StringComparer.Ordinal);
for (int i = 0; i < pairs.Length; i++) var result = new Dictionary<string, string>(pairs.Length, StringComparer.Ordinal);
{ for (int i = 0; i < pairs.Length; i++)
result.Add(pairs[i].Key, pairs[i].Value); {
} result.Add(pairs[i].Key, pairs[i].Value);
return result; }
} return result;
}
/// <summary>
/// Create a dictionary from an array of key/value pairs /// <summary>
/// </summary> /// Create a dictionary from an array of key/value pairs
public static Dictionary<RedisKey, RedisValue> ToDictionary(this KeyValuePair<RedisKey, RedisValue>[] pairs) /// </summary>
{ public static Dictionary<RedisKey, RedisValue> ToDictionary(this KeyValuePair<RedisKey, RedisValue>[] pairs)
if (pairs == null) return null; {
if (pairs == null) return null;
var result = new Dictionary<RedisKey, RedisValue>(pairs.Length);
for (int i = 0; i < pairs.Length; i++) var result = new Dictionary<RedisKey, RedisValue>(pairs.Length);
{ for (int i = 0; i < pairs.Length; i++)
result.Add(pairs[i].Key, pairs[i].Value); {
} result.Add(pairs[i].Key, pairs[i].Value);
return result; }
} return result;
}
/// <summary>
/// Create a dictionary from an array of string pairs /// <summary>
/// </summary> /// Create a dictionary from an array of string pairs
public static Dictionary<string, string> ToDictionary(this KeyValuePair<string, string>[] pairs) /// </summary>
{ public static Dictionary<string, string> ToDictionary(this KeyValuePair<string, string>[] pairs)
if (pairs == null) return null; {
if (pairs == null) return null;
var result = new Dictionary<string, string>(pairs.Length, StringComparer.Ordinal);
for (int i = 0; i < pairs.Length; i++) var result = new Dictionary<string, string>(pairs.Length, StringComparer.Ordinal);
{ for (int i = 0; i < pairs.Length; i++)
result.Add(pairs[i].Key, pairs[i].Value); {
} result.Add(pairs[i].Key, pairs[i].Value);
return result; }
} return result;
}
static readonly string[] nix = new string[0];
/// <summary> static readonly string[] nix = new string[0];
/// Create an array of strings from an array of values /// <summary>
/// </summary> /// Create an array of strings from an array of values
public static string[] ToStringArray(this RedisValue[] values) /// </summary>
{ public static string[] ToStringArray(this RedisValue[] values)
if (values == null) return null; {
if (values.Length == 0) return nix; if (values == null) return null;
return Array.ConvertAll(values, x => (string)x); if (values.Length == 0) return nix;
} return values.Select(x => (string)x).ToArray();
} }
} }
}
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
namespace StackExchange.Redis namespace StackExchange.Redis
{ {
/// <summary> /// <summary>
/// Describes a hash-field (a name/value pair) /// Describes a hash-field (a name/value pair)
/// </summary> /// </summary>
public struct HashEntry : IEquatable<HashEntry> public struct HashEntry : IEquatable<HashEntry>
{ {
internal readonly RedisValue name, value; internal readonly RedisValue name, value;
/// <summary> /// <summary>
/// Initializes a HashEntry value /// Initializes a HashEntry value
/// </summary> /// </summary>
public HashEntry(RedisValue name, RedisValue value) public HashEntry(RedisValue name, RedisValue value)
{ {
this.name = name; this.name = name;
this.value = value; this.value = value;
} }
/// <summary> /// <summary>
/// The name of the hash field /// The name of the hash field
/// </summary> /// </summary>
public RedisValue Name { get { return name; } } public RedisValue Name { get { return name; } }
/// <summary> /// <summary>
/// The value of the hash field /// The value of the hash field
/// </summary> /// </summary>
public RedisValue Value{ get { return value; } } public RedisValue Value{ get { return value; } }
/// <summary> /// <summary>
/// The name of the hash field /// The name of the hash field
/// </summary> /// </summary>
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never), Obsolete("Please use Name", false)] #if !DNXCORE50
public RedisValue Key { get { return name; } } [Browsable(false)]
#endif
/// <summary> [EditorBrowsable(EditorBrowsableState.Never), Obsolete("Please use Name", false)]
/// Converts to a key/value pair public RedisValue Key { get { return name; } }
/// </summary>
public static implicit operator KeyValuePair<RedisValue, RedisValue>(HashEntry value) /// <summary>
{ /// Converts to a key/value pair
return new KeyValuePair<RedisValue, RedisValue>(value.name, value.value); /// </summary>
} public static implicit operator KeyValuePair<RedisValue, RedisValue>(HashEntry value)
/// <summary> {
/// Converts from a key/value pair return new KeyValuePair<RedisValue, RedisValue>(value.name, value.value);
/// </summary> }
public static implicit operator HashEntry(KeyValuePair<RedisValue, RedisValue> value) /// <summary>
{ /// Converts from a key/value pair
return new HashEntry(value.Key, value.Value); /// </summary>
} public static implicit operator HashEntry(KeyValuePair<RedisValue, RedisValue> value)
{
/// <summary> return new HashEntry(value.Key, value.Value);
/// See Object.ToString() }
/// </summary>
public override string ToString() /// <summary>
{ /// See Object.ToString()
return name + ": " + value; /// </summary>
} public override string ToString()
/// <summary> {
/// See Object.GetHashCode() return name + ": " + value;
/// </summary> }
public override int GetHashCode() /// <summary>
{ /// See Object.GetHashCode()
return name.GetHashCode() ^ value.GetHashCode(); /// </summary>
} public override int GetHashCode()
/// <summary> {
/// Compares two values for equality return name.GetHashCode() ^ value.GetHashCode();
/// </summary> }
public override bool Equals(object obj) /// <summary>
{ /// Compares two values for equality
return obj is HashEntry && Equals((HashEntry)obj); /// </summary>
} public override bool Equals(object obj)
{
/// <summary> return obj is HashEntry && Equals((HashEntry)obj);
/// Compares two values for equality }
/// </summary>
public bool Equals(HashEntry value) /// <summary>
{ /// Compares two values for equality
return this.name == value.name && this.value == value.value; /// </summary>
} public bool Equals(HashEntry value)
/// <summary> {
/// Compares two values for equality return this.name == value.name && this.value == value.value;
/// </summary> }
public static bool operator ==(HashEntry x, HashEntry y) /// <summary>
{ /// Compares two values for equality
return x.name == y.name && x.value == y.value; /// </summary>
} public static bool operator ==(HashEntry x, HashEntry y)
/// <summary> {
/// Compares two values for non-equality return x.name == y.name && x.value == y.value;
/// </summary> }
public static bool operator !=(HashEntry x, HashEntry y) /// <summary>
{ /// Compares two values for non-equality
return x.name != y.name || x.value != y.value; /// </summary>
} public static bool operator !=(HashEntry x, HashEntry y)
} {
} return x.name != y.name || x.value != y.value;
}
}
}
#if DNXCORE50
using System;
#endif
using System.Text.RegularExpressions;
namespace StackExchange.Redis
{
internal static class InternalRegexCompiledOption
{
private static readonly RegexOptions RegexCompiledOption;
static InternalRegexCompiledOption()
{
#if DNXCORE50
if (!Enum.TryParse("Compiled", out RegexCompiledOption))
RegexCompiledOption = RegexOptions.None;
#else
RegexCompiledOption = RegexOptions.Compiled;
#endif
}
/// <summary>
/// Gets the default <see cref="RegexOptions"/> to use.
/// <see cref="System.Text.RegularExpressions.RegexOptions.Compiled"/> option isn't available yet for dnxcore50.
/// This returns <see cref="System.Text.RegularExpressions.RegexOptions.Compiled"/> if it is supported;
/// <see cref="System.Text.RegularExpressions.RegexOptions.None"/> otherwise.
/// </summary>
public static RegexOptions Default
{
get
{
return RegexCompiledOption;
}
}
}
}
...@@ -119,7 +119,7 @@ internal void ExtractParameters(object ps, RedisKey? keyPrefix, out RedisKey[] k ...@@ -119,7 +119,7 @@ internal void ExtractParameters(object ps, RedisKey? keyPrefix, out RedisKey[] k
{ {
string missingMember; string missingMember;
string badMemberType; string badMemberType;
if(!ScriptParameterMapper.IsValidParameterHash(psType, this, out missingMember, out badMemberType)) if (!ScriptParameterMapper.IsValidParameterHash(psType, this, out missingMember, out badMemberType))
{ {
if (missingMember != null) if (missingMember != null)
{ {
......
...@@ -2,7 +2,9 @@ ...@@ -2,7 +2,9 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
#if FEATURE_SERIALIZATION
using System.Runtime.Serialization; using System.Runtime.Serialization;
#endif
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
...@@ -11,22 +13,29 @@ namespace StackExchange.Redis ...@@ -11,22 +13,29 @@ namespace StackExchange.Redis
/// <summary> /// <summary>
/// Indicates that a command was illegal and was not sent to the server /// Indicates that a command was illegal and was not sent to the server
/// </summary> /// </summary>
#if FEATURE_SERIALIZATION
[Serializable] [Serializable]
#endif
public sealed class RedisCommandException : Exception public sealed class RedisCommandException : Exception
{ {
#if FEATURE_SERIALIZATION
private RedisCommandException(SerializationInfo info, StreamingContext ctx) : base(info, ctx) { } private RedisCommandException(SerializationInfo info, StreamingContext ctx) : base(info, ctx) { }
#endif
internal RedisCommandException(string message) : base(message) { } internal RedisCommandException(string message) : base(message) { }
internal RedisCommandException(string message, Exception innerException) : base(message, innerException) { } internal RedisCommandException(string message, Exception innerException) : base(message, innerException) { }
} }
/// <summary> /// <summary>
/// Indicates a connection fault when communicating with redis /// Indicates a connection fault when communicating with redis
/// </summary> /// </summary>
#if FEATURE_SERIALIZATION
[Serializable] [Serializable]
#endif
public sealed class RedisConnectionException : RedisException public sealed class RedisConnectionException : RedisException
{ {
#if FEATURE_SERIALIZATION
private RedisConnectionException(SerializationInfo info, StreamingContext ctx) : base(info, ctx) private RedisConnectionException(SerializationInfo info, StreamingContext ctx) : base(info, ctx)
{ {
this.FailureType = (ConnectionFailureType)info.GetInt32("failureType"); this.FailureType = (ConnectionFailureType)info.GetInt32("failureType");
...@@ -39,6 +48,7 @@ public override void GetObjectData(SerializationInfo info, StreamingContext cont ...@@ -39,6 +48,7 @@ public override void GetObjectData(SerializationInfo info, StreamingContext cont
base.GetObjectData(info, context); base.GetObjectData(info, context);
info.AddValue("failureType", (int)this.FailureType); info.AddValue("failureType", (int)this.FailureType);
} }
#endif
internal RedisConnectionException(ConnectionFailureType failureType, string message) : base(message) internal RedisConnectionException(ConnectionFailureType failureType, string message) : base(message)
{ {
...@@ -54,28 +64,36 @@ internal RedisConnectionException(ConnectionFailureType failureType, string mess ...@@ -54,28 +64,36 @@ internal RedisConnectionException(ConnectionFailureType failureType, string mess
/// </summary> /// </summary>
public ConnectionFailureType FailureType { get; private set; } public ConnectionFailureType FailureType { get; private set; }
} }
/// <summary> /// <summary>
/// Indicates an issue communicating with redis /// Indicates an issue communicating with redis
/// </summary> /// </summary>
#if FEATURE_SERIALIZATION
[Serializable] [Serializable]
#endif
public class RedisException : Exception public class RedisException : Exception
{ {
/// <summary> /// <summary>
/// Deserialization constructor; not intended for general usage /// Deserialization constructor; not intended for general usage
/// </summary> /// </summary>
#if FEATURE_SERIALIZATION
protected RedisException(SerializationInfo info, StreamingContext ctx) : base(info, ctx) { } protected RedisException(SerializationInfo info, StreamingContext ctx) : base(info, ctx) { }
#endif
internal RedisException(string message) : base(message) { } internal RedisException(string message) : base(message) { }
internal RedisException(string message, Exception innerException) : base(message, innerException) { } internal RedisException(string message, Exception innerException) : base(message, innerException) { }
} }
/// <summary> /// <summary>
/// Indicates an exception raised by a redis server /// Indicates an exception raised by a redis server
/// </summary> /// </summary>
#if FEATURE_SERIALIZATION
[Serializable] [Serializable]
#endif
public sealed class RedisServerException : RedisException public sealed class RedisServerException : RedisException
{ {
#if FEATURE_SERIALIZATION
private RedisServerException(SerializationInfo info, StreamingContext ctx) : base(info, ctx) { } private RedisServerException(SerializationInfo info, StreamingContext ctx) : base(info, ctx) { }
#endif
internal RedisServerException(string message) : base(message) { } internal RedisServerException(string message) : base(message) { }
} }
......
...@@ -394,7 +394,7 @@ internal void OnHeartbeat(bool ifConnectedOnly) ...@@ -394,7 +394,7 @@ internal void OnHeartbeat(bool ifConnectedOnly)
switch (state) switch (state)
{ {
case (int)State.Connecting: case (int)State.Connecting:
int connectTimeMilliseconds = unchecked(Environment.TickCount - Thread.VolatileRead(ref connectStartTicks)); int connectTimeMilliseconds = unchecked(Environment.TickCount - VolatileWrapper.Read(ref connectStartTicks));
if (connectTimeMilliseconds >= multiplexer.RawConfig.ConnectTimeout) if (connectTimeMilliseconds >= multiplexer.RawConfig.ConnectTimeout)
{ {
Trace("Aborting connect"); Trace("Aborting connect");
......
using System; using System;
#if DNXCORE50
using System.Collections.Generic;
using System.Reflection;
#endif
using System.Text; using System.Text;
namespace StackExchange.Redis namespace StackExchange.Redis
...@@ -300,9 +304,14 @@ public int CompareTo(RedisValue other) ...@@ -300,9 +304,14 @@ public int CompareTo(RedisValue other)
{ {
if (otherType == CompareType.Int64) return thisDouble.CompareTo((double)otherInt64); if (otherType == CompareType.Int64) return thisDouble.CompareTo((double)otherInt64);
if (otherType == CompareType.Double) return thisDouble.CompareTo(otherDouble); if (otherType == CompareType.Double) return thisDouble.CompareTo(otherDouble);
} }
// otherwise, compare as strings // otherwise, compare as strings
#if !DNXCORE50
return StringComparer.InvariantCulture.Compare((string)this, (string)other); return StringComparer.InvariantCulture.Compare((string)this, (string)other);
#else
var compareInfo = System.Globalization.CultureInfo.InvariantCulture.CompareInfo;
return compareInfo.Compare((string)this, (string)other, System.Globalization.CompareOptions.IgnoreCase);
#endif
} }
catch(Exception ex) catch(Exception ex)
{ {
...@@ -601,7 +610,7 @@ object IConvertible.ToType(Type conversionType, IFormatProvider provider) ...@@ -601,7 +610,7 @@ object IConvertible.ToType(Type conversionType, IFormatProvider provider)
if (conversionType== null) throw new ArgumentNullException("conversionType"); if (conversionType== null) throw new ArgumentNullException("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(Type.GetTypeCode(conversionType)) 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;
...@@ -703,5 +712,49 @@ public bool TryParse(out double val) ...@@ -703,5 +712,49 @@ public bool TryParse(out double val)
return TryParseDouble(blob, out val); return TryParseDouble(blob, out val);
} }
} }
internal static class ReflectionExtensions
{
#if DNXCORE50
internal static TypeCode GetTypeCode(this Type type)
{
if (type == null) return TypeCode.Empty;
TypeCode result;
if (typeCodeLookup.TryGetValue(type, out result)) return result;
if (type.GetTypeInfo().IsEnum)
{
type = Enum.GetUnderlyingType(type);
if (typeCodeLookup.TryGetValue(type, out result)) return result;
}
return TypeCode.Object;
}
static readonly Dictionary<Type, TypeCode> typeCodeLookup = new Dictionary<Type, TypeCode>
{
{typeof(bool), TypeCode.Boolean },
{typeof(byte), TypeCode.Byte },
{typeof(char), TypeCode.Char},
{typeof(DateTime), TypeCode.DateTime},
{typeof(decimal), TypeCode.Decimal},
{typeof(double), TypeCode.Double },
{typeof(short), TypeCode.Int16 },
{typeof(int), TypeCode.Int32 },
{typeof(long), TypeCode.Int64 },
{typeof(object), TypeCode.Object},
{typeof(sbyte), TypeCode.SByte },
{typeof(float), TypeCode.Single },
{typeof(string), TypeCode.String },
{typeof(ushort), TypeCode.UInt16 },
{typeof(uint), TypeCode.UInt32 },
{typeof(ulong), TypeCode.UInt64 },
};
#else
internal static TypeCode GetTypeCode(this Type type)
{
return type.GetTypeCode();
}
#endif
}
} }
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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