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
bin
bin.snk
obj
*.suo
*.user
*.nupkg
packages/NuGet.CommandLine.*
*.sln.docstates
_ReSharper.*
Mono/
*.sln.ide
*.rdb
*.aof
*.orig
redis-cli.exe
Redis Configs/*.dat
RedisQFork*.dat
StackExchange.Redis.*.zip
\ No newline at end of file
.hg
bin
bin.snk
obj
*.suo
*.user
*.nupkg
packages/NuGet.CommandLine.*
*.sln.docstates
_ReSharper.*
Mono/
*.sln.ide
*.rdb
*.aof
*.orig
redis-cli.exe
Redis Configs/*.dat
RedisQFork*.dat
StackExchange.Redis.*.zip
.vs/
*.lock.json
\ No newline at end of file
......@@ -35,9 +35,17 @@ static void MassiveBulkOpsAsync(int AsyncOpsQty, bool preserveOrder, bool withCo
var conn = muxer.GetDatabase();
muxer.Wait(conn.PingAsync());
int number = 0;
Action<Task> nonTrivial = delegate
{
#if !DNXCORE50
Thread.SpinWait(5);
#else
for (int i = 0; i < 50; i++)
{
number++;
}
#endif
};
var watch = Stopwatch.StartNew();
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()
}
}
[Test, ExpectedException(typeof(RedisConnectionException))]
[Test]
public void CanNotOpenNonsenseConnection_IP()
{
var log = new StringWriter();
try {
using (var conn = ConnectionMultiplexer.Connect(Config.LocalHost + ":6500")) { }
} finally {
Console.WriteLine(log);
}
Assert.Throws<RedisConnectionException>(() =>
{
var log = new StringWriter();
try {
using (var conn = ConnectionMultiplexer.Connect(Config.LocalHost + ":6500")) { }
}
finally {
Console.WriteLine(log);
}
});
}
[Test, ExpectedException(typeof(RedisConnectionException))]
[Test]
public void CanNotOpenNonsenseConnection_DNS()
{
var log = new StringWriter();
try {
using (var conn = ConnectionMultiplexer.Connect("doesnot.exist.ds.aasd981230d.com:6500", log)) { }
} finally {
Console.WriteLine(log);
}
Assert.Throws<RedisConnectionException>(() =>
{
var log = new StringWriter();
try
{
using (var conn = ConnectionMultiplexer.Connect("doesnot.exist.ds.aasd981230d.com:6500", log)) { }
}
finally
{
Console.WriteLine(log);
}
});
}
[Test]
......
......@@ -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()
{
using (var muxer = Config.GetUnsecuredConnection())
Assert.Throws<RedisConnectionException>(() =>
{
var conn = muxer.GetDatabase(0);
var task = new { priority = 3 };
conn.KeyDeleteAsync("item:1");
conn.StringSetAsync("item:1", "not a hash");
conn.HashSetAsync("item:1", "priority", task.priority.ToString());
using (var muxer = Config.GetUnsecuredConnection())
{
var conn = muxer.GetDatabase(0);
var task = new { priority = 3 };
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
{
conn.Wait(taskResult);
Assert.Fail();
} catch(AggregateException ex)
{
throw ex.InnerExceptions[0];
try
{
conn.Wait(taskResult);
Assert.Fail();
}
catch (AggregateException ex)
{
throw ex.InnerExceptions[0];
}
}
}
},
message: "WRONGTYPE Operation against a key holding the wrong kind of value");
}
}
}
......@@ -44,9 +44,9 @@
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="nunit.framework, Version=2.6.4.14350, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\NUnit.2.6.4\lib\nunit.framework.dll</HintPath>
<Reference Include="nunit.framework, Version=3.0.5797.27534, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
<HintPath>..\packages\NUnit.3.0.0\lib\net45\nunit.framework.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
......
......@@ -100,7 +100,6 @@ where Attribute.IsDefined(method, typeof(TestAttribute))
foreach (var test in tests)
{
var expectedFail = Attribute.GetCustomAttribute(test, typeof(ExpectedExceptionAttribute)) as ExpectedExceptionAttribute;
Console.Write(test.Name + ": ");
Exception err = null;
......@@ -131,35 +130,6 @@ where Attribute.IsDefined(method, typeof(TestAttribute))
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)
{
Console.WriteLine("pass");
......
......@@ -264,21 +264,26 @@ public void NonAsciiScripts()
}
}
[Test, ExpectedException(typeof(RedisServerException), ExpectedMessage = "oops")]
[Test]
public void ScriptThrowsError()
{
using (var muxer = GetScriptConn())
Assert.Throws<RedisServerException>(() =>
{
var conn = muxer.GetDatabase(0);
var result = conn.ScriptEvaluateAsync("return redis.error_reply('oops')", null, null);
try
using (var muxer = GetScriptConn())
{
conn.Wait(result);
} catch(AggregateException ex)
{
throw ex.InnerExceptions[0];
var conn = muxer.GetDatabase(0);
var result = conn.ScriptEvaluateAsync("return redis.error_reply('oops')", null, null);
try
{
conn.Wait(result);
}
catch (AggregateException ex)
{
throw ex.InnerExceptions[0];
}
}
}
},
message: "oops");
}
[Test]
......
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="NUnit" version="2.6.4" targetFramework="net45" />
<package id="NUnit" version="3.0.0" targetFramework="net45" />
</packages>
\ No newline at end of file
This diff is collapsed.
using System;
#if FEATURE_MOQ
using System;
using Moq;
using NUnit.Framework;
using StackExchange.Redis.KeyspaceIsolation;
......@@ -12,7 +13,8 @@ public sealed class BatchWrapperTests
private Mock<IBatch> mock;
private BatchWrapper wrapper;
[TestFixtureSetUp]
//[TestFixtureSetUp]
[OneTimeSetUpAttribute]
public void Initialize()
{
mock = new Mock<IBatch>();
......@@ -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()
}
[Test]
[ExpectedException(typeof(RedisCommandException), ExpectedMessage = "This operation has been disabled in the command-map and cannot be used: CONFIG")]
public void ReadConfigWithConfigDisabled()
{
using (var muxer = Create(allowAdmin: true, disabledCommands: new[] { "config", "info" }))
{
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]
......@@ -144,7 +147,11 @@ public void ReadConfig()
var all = conn.ConfigGet();
Assert.IsTrue(all.Length > 0, "any");
#if !DNXCORE50
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.IsTrue(pairs.ContainsKey("timeout"), "timeout");
......@@ -157,7 +164,7 @@ public void ReadConfig()
}
[Test]
public async void TestConfigureAsync()
public async System.Threading.Tasks.Task TestConfigureAsync()
{
using(var muxer = Create())
{
......
using System;
#if FEATURE_MOQ
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Net;
......@@ -15,7 +16,8 @@ public sealed class DatabaseWrapperTests
private Mock<IDatabase> mock;
private DatabaseWrapper wrapper;
[TestFixtureSetUp]
//[TestFixtureSetUp]
[OneTimeSetUp]
public void Initialize()
{
mock = new Mock<IDatabase>();
......@@ -289,10 +291,9 @@ public void KeyPersist()
}
[Test]
[ExpectedException(typeof(NotSupportedException))]
public void KeyRandom()
{
wrapper.KeyRandom();
Assert.Throws<NotSupportedException>(() => wrapper.KeyRandom());
}
[Test]
......@@ -933,3 +934,4 @@ public void StringSetRange()
}
}
}
#endif
\ No newline at end of file
......@@ -23,15 +23,21 @@ public void UnkonwnKeywordHandling_Ignore()
{
var options = ConfigurationOptions.Parse("ssl2=true", true);
}
[Test, ExpectedException(typeof(ArgumentException), ExpectedMessage = "Keyword 'ssl2' is not supported")]
[Test]
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()
{
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
{
protected override string GetConfiguration()
{
return "127.0.0.1";
return "127.0.0.1:6379";
}
[Test]
public async void Execute()
......
......@@ -127,7 +127,7 @@ public enum TestMode
NoMultiExec,
Twemproxy
}
public IEnumerable<TestMode> TestModes()
public static IEnumerable<TestMode> TestModes()
{
return (TestMode[])Enum.GetValues(typeof(TestMode));
}
......
......@@ -14,16 +14,19 @@ protected override string GetConfiguration()
return PrimaryServer + ":" + SecurePort + "," + PrimaryServer + ":" + PrimaryPort + ",password=" + SecurePassword;
}
[Test, ExpectedException(typeof(RedisCommandException), ExpectedMessage = "Command cannot be issued to a slave: FLUSHDB")]
[Test]
public void CannotFlushSlave()
{
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);
slave.FlushDatabase();
}
Assert.Throws<RedisCommandException>(() => {
ConfigurationOptions config = GetMasterSlaveConfig();
using (var conn = ConnectionMultiplexer.Connect(config))
{
var servers = conn.GetEndPoints().Select(e => conn.GetServer(e));
var slave = servers.First(x => x.IsSlave);
slave.FlushDatabase();
}
},
"Command cannot be issued to a slave: FLUSHDB");
}
[Test]
......
......@@ -17,7 +17,7 @@ public class Naming
public void CheckSignatures(Type type, bool isAsync)
{
// 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);
foreach(var member in members)
{
......@@ -29,9 +29,9 @@ public void CheckSignatures(Type type, bool isAsync)
[Test]
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");
var cmd = typeof(ConnectionMultiplexer).Assembly.GetType("StackExchange.Redis.RedisCommand");
var cmd = typeof(ConnectionMultiplexer).GetTypeInfo().Assembly.GetType("StackExchange.Redis.RedisCommand");
Assert.IsNotNull(cmd, "RedisCommand");
var method = msg.GetMethod("IsMasterOnly", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
Assert.IsNotNull(method, "IsMasterOnly");
......@@ -89,7 +89,7 @@ static bool UsesKey(Type type)
{
if (UsesKey(type.GetElementType())) return true;
}
if(type.IsGenericType) // KVP, etc
if(type.GetTypeInfo().IsGenericType) // KVP, etc
{
var args = type.GetGenericArguments();
if (args.Any(UsesKey)) return true;
......@@ -139,7 +139,7 @@ public void CheckSyncAsyncMethodsMatch(Type from, Type to)
{
huntType = null;
}
else if (method.ReturnType.IsSubclassOf(typeof(Task)))
else if (method.ReturnType.GetTypeInfo().IsSubclassOf(typeof(Task)))
{
huntType = method.ReturnType.GetGenericArguments()[0];
}
......@@ -148,9 +148,14 @@ public void CheckSyncAsyncMethodsMatch(Type from, Type to)
huntType = typeof(Task<>).MakeGenericType(method.ReturnType);
}
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());
#if !DNXCORE50
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);
var pTo = found.GetParameters();
......@@ -166,16 +171,24 @@ public void CheckSyncAsyncMethodsMatch(Type from, Type to)
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)
{
#if DEBUG
#if !DNXCORE50
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);
if((bool)attrib.GetType().GetProperty("IgnoreEntireMethod").GetValue(attrib))
#else
Attribute attrib = method.GetCustomAttribute(ignoreType);
#endif
if ((bool)attrib.GetType().GetProperty("IgnoreEntireMethod").GetValue(attrib))
{
return;
}
......@@ -212,4 +225,34 @@ void CheckName(MemberInfo member, bool isAsync)
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 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
#if DNXCORE50
using System.Reflection;
#endif
using System.Threading.Tasks;
using NUnit.Framework;
using System.Threading;
......@@ -456,11 +459,11 @@ public void LowAllocationEnumerable()
conn.WaitAll(allTasks.ToArray());
var res = conn.FinishProfiling(profiler.MyContext);
Assert.IsTrue(res.GetType().IsValueType);
Assert.IsTrue(res.GetType().GetTypeInfo().IsValueType);
using(var e = res.GetEnumerator())
{
Assert.IsTrue(e.GetType().IsValueType);
Assert.IsTrue(e.GetType().GetTypeInfo().IsValueType);
Assert.IsTrue(e.MoveNext());
var i = e.Current;
......
......@@ -38,17 +38,17 @@ public void ExplicitPublishMode()
Thread.Sleep(1000);
pub.Publish("abcd", "efg");
Thread.Sleep(500);
Assert.AreEqual(0, Thread.VolatileRead(ref a), "a1");
Assert.AreEqual(1, Thread.VolatileRead(ref b), "b1");
Assert.AreEqual(1, Thread.VolatileRead(ref c), "c1");
Assert.AreEqual(1, Thread.VolatileRead(ref d), "d1");
Assert.AreEqual(0, VolatileWrapper.Read(ref a), "a1");
Assert.AreEqual(1, VolatileWrapper.Read(ref b), "b1");
Assert.AreEqual(1, VolatileWrapper.Read(ref c), "c1");
Assert.AreEqual(1, VolatileWrapper.Read(ref d), "d1");
pub.Publish("*bcd", "efg");
Thread.Sleep(500);
Assert.AreEqual(1, Thread.VolatileRead(ref a), "a2");
//Assert.AreEqual(1, Thread.VolatileRead(ref b), "b2");
//Assert.AreEqual(1, Thread.VolatileRead(ref c), "c2");
//Assert.AreEqual(1, Thread.VolatileRead(ref d), "d2");
Assert.AreEqual(1, VolatileWrapper.Read(ref a), "a2");
//Assert.AreEqual(1, VolatileWrapper.Read(ref b), "b2");
//Assert.AreEqual(1, VolatileWrapper.Read(ref c), "c2");
//Assert.AreEqual(1, VolatileWrapper.Read(ref d), "d2");
}
}
......@@ -101,7 +101,7 @@ public void TestBasicPubSub(bool preserveOrder, string channelPrefix, bool wildC
{
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");
Ping(muxer, pub, sub, 3);
......@@ -110,7 +110,7 @@ public void TestBasicPubSub(bool preserveOrder, string channelPrefix, bool wildC
{
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
sub.Unsubscribe(subChannel, handler1);
......@@ -120,7 +120,7 @@ public void TestBasicPubSub(bool preserveOrder, string channelPrefix, bool wildC
{
Assert.AreEqual(1, received.Count);
}
Assert.AreEqual(2, Thread.VolatileRead(ref secondHandler));
Assert.AreEqual(2, VolatileWrapper.Read(ref secondHandler));
Assert.AreEqual(1, count);
// unsubscribe from second; should see nothing this time
......@@ -131,7 +131,7 @@ public void TestBasicPubSub(bool preserveOrder, string channelPrefix, bool wildC
{
Assert.AreEqual(1, received.Count);
}
Assert.AreEqual(2, Thread.VolatileRead(ref secondHandler));
Assert.AreEqual(2, VolatileWrapper.Read(ref secondHandler));
Assert.AreEqual(0, count);
}
}
......@@ -172,7 +172,7 @@ public void TestBasicPubSubFireAndForget(bool preserveOrder)
{
Assert.AreEqual(0, received.Count);
}
Assert.AreEqual(0, Thread.VolatileRead(ref secondHandler));
Assert.AreEqual(0, VolatileWrapper.Read(ref secondHandler));
Ping(muxer, pub, sub);
var count = sub.Publish(key, "def", CommandFlags.FireAndForget);
Ping(muxer, pub, sub);
......@@ -181,7 +181,7 @@ public void TestBasicPubSubFireAndForget(bool preserveOrder)
{
Assert.AreEqual(1, received.Count);
}
Assert.AreEqual(1, Thread.VolatileRead(ref secondHandler));
Assert.AreEqual(1, VolatileWrapper.Read(ref secondHandler));
sub.Unsubscribe(key);
count = sub.Publish(key, "ghi", CommandFlags.FireAndForget);
......@@ -247,7 +247,7 @@ public void TestPatternPubSub(bool preserveOrder)
{
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");
Ping(muxer, pub, sub);
......@@ -256,7 +256,7 @@ public void TestPatternPubSub(bool preserveOrder)
{
Assert.AreEqual(1, received.Count);
}
Assert.AreEqual(1, Thread.VolatileRead(ref secondHandler));
Assert.AreEqual(1, VolatileWrapper.Read(ref secondHandler));
sub.Unsubscribe("a*c");
count = sub.Publish("abc", "ghi");
......@@ -392,7 +392,7 @@ public void SubscriptionsSurviveConnectionFailure()
});
sub.Publish(channel, "abc");
sub.Ping();
Assert.AreEqual(1, Thread.VolatileRead(ref counter), "counter");
Assert.AreEqual(1, VolatileWrapper.Read(ref counter), "counter");
var server = GetServer(muxer);
Assert.AreEqual(1, server.GetCounters().Subscription.SocketCount, "sockets");
......@@ -408,8 +408,20 @@ public void SubscriptionsSurviveConnectionFailure()
#endif
sub.Publish(channel, "abc");
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()
var db = conn.GetDatabase();
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);
db.ScriptEvaluate(hexHash, keys);
......
......@@ -68,14 +68,16 @@ public void Connect()
[Test]
[TestCase("wrong")]
[TestCase("")]
[ExpectedException(typeof(RedisConnectionException), ExpectedMessage = "No connection is available to service this operation: PING")]
public void ConnectWithWrongPassword(string password)
{
SetExpectedAmbientFailureCount(-1);
using (var server = Create(password: password, checkConnect: false))
{
server.GetDatabase().Ping();
}
Assert.Throws<RedisConnectionException>(() => {
SetExpectedAmbientFailureCount(-1);
using (var server = Create(password: password, checkConnect: false))
{
server.GetDatabase().Ping();
}
},
"No connection is available to service this operation: PING");
}
}
}
......@@ -6,7 +6,7 @@
namespace StackExchange.Redis.Tests
{
[TestFixture, Ignore]
[TestFixture, Ignore("reason?")]
public class Sentinel
{
// TODO fill in these constants before running tests
......@@ -100,7 +100,7 @@ public void SentinelSlavesTest()
}
}
[Test, Ignore]
[Test, Ignore("reason?")]
public void SentinelFailoverTest()
{
Server.SentinelFailover(ServiceName);
......
......@@ -18,7 +18,7 @@
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<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>
<WarningLevel>4</WarningLevel>
<PlatformTarget>AnyCPU</PlatformTarget>
......@@ -28,14 +28,14 @@
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE;PLAT_SAFE_CONTINUATIONS</DefineConstants>
<DefineConstants>TRACE;PLAT_SAFE_CONTINUATIONS;FEATURE_BOOKSLEEVE;FEATURE_MOQ</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Verbose|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\Verbose\</OutputPath>
<DefineConstants>TRACE;DEBUG;VERBOSE</DefineConstants>
<DefineConstants>TRACE;DEBUG;VERBOSE;FEATURE_BOOKSLEEVE;FEATURE_MOQ</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
......@@ -45,7 +45,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Log Output|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\Log Output\</OutputPath>
<DefineConstants>TRACE;DEBUG;LOGOUTPUT</DefineConstants>
<DefineConstants>TRACE;DEBUG;LOGOUTPUT;FEATURE_BOOKSLEEVE;FEATURE_MOQ</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
......@@ -53,7 +53,7 @@
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Mono|AnyCPU'">
<OutputPath>bin\Mono\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<DefineConstants>TRACE;FEATURE_BOOKSLEEVE;FEATURE_MOQ</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
......@@ -68,9 +68,9 @@
<HintPath>..\packages\Moq.4.2.1502.0911\lib\net40\Moq.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="nunit.framework, Version=2.6.4.14350, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\NUnit.2.6.4\lib\nunit.framework.dll</HintPath>
<Reference Include="nunit.framework, Version=3.0.5797.27534, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
<HintPath>..\packages\NUnit.3.0.0\lib\net45\nunit.framework.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
......
......@@ -8,7 +8,9 @@
using System.Text;
using System.Threading;
using System.Threading.Tasks;
#if FEATURE_BOOKSLEEVE
using BookSleeve;
#endif
using NUnit.Framework;
namespace StackExchange.Redis.Tests
......@@ -221,6 +223,7 @@ protected static string Me([CallerMemberName] string caller = null)
return caller;
}
#if FEATURE_BOOKSLEEVE
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);
......@@ -239,7 +242,7 @@ private static RedisConnection GetOldStyleConnection(string host, int port, bool
}
return conn;
}
#endif
protected static TimeSpan RunConcurrent(Action work, int threads, int timeout = 10000, [CallerMemberName] string caller = null)
{
if (work == null) throw new ArgumentNullException("work");
......@@ -282,11 +285,13 @@ protected static TimeSpan RunConcurrent(Action work, int threads, int 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];
if (thd.IsAlive) thd.Abort();
}
#endif
throw new TimeoutException();
}
......
using System.Text;
#if FEATURE_MOQ
using System.Text;
using Moq;
using NUnit.Framework;
using StackExchange.Redis.KeyspaceIsolation;
......@@ -11,7 +12,7 @@ public sealed class TransactionWrapperTests
private Mock<ITransaction> mock;
private TransactionWrapper wrapper;
[TestFixtureSetUp]
[OneTimeSetUp]
public void Initialize()
{
mock = new Mock<ITransaction>();
......@@ -89,3 +90,4 @@ public void Execute()
}
}
}
#endif
\ No newline at end of file
using System;
using NUnit.Framework;
using StackExchange.Redis.KeyspaceIsolation;
namespace StackExchange.Redis.Tests
{
[TestFixture]
public class WithKeyPrefixTests : TestBase
{
[Test]
public void BlankPrefixYieldsSame_Bytes()
{
using (var conn = Create())
{
var raw = conn.GetDatabase(1);
var prefixed = raw.WithKeyPrefix(new byte[0]);
Assert.AreSame(raw, prefixed);
}
}
[Test]
public void BlankPrefixYieldsSame_String()
{
using (var conn = Create())
{
var raw = conn.GetDatabase(1);
var prefixed = raw.WithKeyPrefix("");
Assert.AreSame(raw, prefixed);
}
}
[Test, ExpectedException(typeof(ArgumentNullException))]
public void NullPrefixIsError_Bytes()
{
using (var conn = Create())
{
var raw = conn.GetDatabase(1);
var prefixed = raw.WithKeyPrefix((byte[])null);
}
}
[Test, ExpectedException(typeof(ArgumentNullException))]
public void NullPrefixIsError_String()
{
using (var conn = Create())
{
var raw = conn.GetDatabase(1);
var prefixed = raw.WithKeyPrefix((string)null);
}
}
[Test, ExpectedException(typeof(ArgumentNullException))]
[TestCase("abc")]
[TestCase("")]
[TestCase(null)]
public void NullDatabaseIsError(string prefix)
{
IDatabase raw = null;
var prefixed = raw.WithKeyPrefix(prefix);
}
[Test]
public void BasicSmokeTest()
{
using(var conn = Create())
{
var raw = conn.GetDatabase(1);
var foo = raw.WithKeyPrefix("foo");
var foobar = foo.WithKeyPrefix("bar");
string key = Me();
string s = Guid.NewGuid().ToString(), t = Guid.NewGuid().ToString();
foo.StringSet(key, s);
var val = (string)foo.StringGet(key);
Assert.AreEqual(s, val); // fooBasicSmokeTest
foobar.StringSet(key, t);
val = (string)foobar.StringGet(key);
Assert.AreEqual(t, val); // foobarBasicSmokeTest
val = (string)foo.StringGet("bar" + key);
Assert.AreEqual(t, val); // foobarBasicSmokeTest
val = (string)raw.StringGet("foo" + key);
Assert.AreEqual(s, val); // fooBasicSmokeTest
val = (string)raw.StringGet("foobar" + key);
Assert.AreEqual(t, val); // foobarBasicSmokeTest
}
}
[Test]
public void ConditionTest()
{
using(var conn = Create())
{
var raw = conn.GetDatabase(2);
var foo = raw.WithKeyPrefix("tran:");
raw.KeyDelete("tran:abc");
raw.KeyDelete("tran:i");
// execute while key exists
raw.StringSet("tran:abc", "def");
var tran = foo.CreateTransaction();
tran.AddCondition(Condition.KeyExists("abc"));
tran.StringIncrementAsync("i");
tran.Execute();
int 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;
using NUnit.Framework;
using StackExchange.Redis.KeyspaceIsolation;
namespace StackExchange.Redis.Tests
{
[TestFixture]
public class WithKeyPrefixTests : TestBase
{
[Test]
public void BlankPrefixYieldsSame_Bytes()
{
using (var conn = Create())
{
var raw = conn.GetDatabase(1);
var prefixed = raw.WithKeyPrefix(new byte[0]);
Assert.AreSame(raw, prefixed);
}
}
[Test]
public void BlankPrefixYieldsSame_String()
{
using (var conn = Create())
{
var raw = conn.GetDatabase(1);
var prefixed = raw.WithKeyPrefix("");
Assert.AreSame(raw, prefixed);
}
}
[Test]
public void NullPrefixIsError_Bytes()
{
Assert.Throws<ArgumentNullException>(() => {
using (var conn = Create())
{
var raw = conn.GetDatabase(1);
var prefixed = raw.WithKeyPrefix((byte[])null);
}
});
}
[Test]
public void NullPrefixIsError_String()
{
Assert.Throws<ArgumentNullException>(() => {
using (var conn = Create())
{
var raw = conn.GetDatabase(1);
var prefixed = raw.WithKeyPrefix((string)null);
}
});
}
[Test]
[TestCase("abc")]
[TestCase("")]
[TestCase(null)]
public void NullDatabaseIsError(string prefix)
{
Assert.Throws<ArgumentNullException>(() => {
IDatabase raw = null;
var prefixed = raw.WithKeyPrefix(prefix);
});
}
[Test]
public void BasicSmokeTest()
{
using(var conn = Create())
{
var raw = conn.GetDatabase(1);
var foo = raw.WithKeyPrefix("foo");
var foobar = foo.WithKeyPrefix("bar");
string key = Me();
string s = Guid.NewGuid().ToString(), t = Guid.NewGuid().ToString();
foo.StringSet(key, s);
var val = (string)foo.StringGet(key);
Assert.AreEqual(s, val); // fooBasicSmokeTest
foobar.StringSet(key, t);
val = (string)foobar.StringGet(key);
Assert.AreEqual(t, val); // foobarBasicSmokeTest
val = (string)foo.StringGet("bar" + key);
Assert.AreEqual(t, val); // foobarBasicSmokeTest
val = (string)raw.StringGet("foo" + key);
Assert.AreEqual(s, val); // fooBasicSmokeTest
val = (string)raw.StringGet("foobar" + key);
Assert.AreEqual(t, val); // foobarBasicSmokeTest
}
}
[Test]
public void ConditionTest()
{
using(var conn = Create())
{
var raw = conn.GetDatabase(2);
var foo = raw.WithKeyPrefix("tran:");
raw.KeyDelete("tran:abc");
raw.KeyDelete("tran:i");
// execute while key exists
raw.StringSet("tran:abc", "def");
var tran = foo.CreateTransaction();
tran.AddCondition(Condition.KeyExists("abc"));
tran.StringIncrementAsync("i");
tran.Execute();
int 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.Linq.Expressions;
using System.Net;
......@@ -15,7 +16,8 @@ public sealed class WrapperBaseTests
private Mock<IDatabaseAsync> mock;
private WrapperBase<IDatabaseAsync> wrapper;
[TestFixtureSetUp]
//[TestFixtureSetUp]
[OneTimeSetUp]
public void Initialize()
{
mock = new Mock<IDatabaseAsync>();
......@@ -258,10 +260,11 @@ public void KeyPersistAsync()
}
[Test]
[ExpectedException(typeof(NotSupportedException))]
public void KeyRandomAsync()
{
wrapper.KeyRandomAsync();
Assert.Throws<NotSupportedException>(() => {
wrapper.KeyRandomAsync();
});
}
[Test]
......@@ -888,3 +891,4 @@ public void StringSetRangeAsync()
}
}
}
#endif
\ No newline at end of file
......@@ -2,5 +2,5 @@
<packages>
<package id="BookSleeve" version="1.3.41" 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>
\ 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 @@
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>TRACE;DEBUG</DefineConstants>
<DefineConstants>TRACE;DEBUG;FEATURE_SERIALIZATION FEATURE_SOCKET_MODE_POLL</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
......@@ -27,7 +27,7 @@
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<DefineConstants>TRACE;FEATURE_SERIALIZATION FEATURE_SOCKET_MODE_POLL</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
......@@ -36,7 +36,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Verbose|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\Verbose\</OutputPath>
<DefineConstants>TRACE;DEBUG;VERBOSE</DefineConstants>
<DefineConstants>TRACE;DEBUG;VERBOSE;FEATURE_SERIALIZATION FEATURE_SOCKET_MODE_POLL</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DocumentationFile>bin\Debug\StackExchange.Redis.xml</DocumentationFile>
<DebugType>full</DebugType>
......@@ -48,7 +48,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Log Output|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\Log Output\</OutputPath>
<DefineConstants>TRACE;DEBUG;LOGOUTPUT</DefineConstants>
<DefineConstants>TRACE;DEBUG;LOGOUTPUT FEATURE_SERIALIZATION FEATURE_SOCKET_MODE_POLL</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DocumentationFile>bin\Debug\StackExchange.Redis.xml</DocumentationFile>
<DebugType>full</DebugType>
......@@ -58,7 +58,7 @@
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Mono|AnyCPU'">
<OutputPath>bin\Mono\</OutputPath>
<DefineConstants>TRACE;__MonoCS__</DefineConstants>
<DefineConstants>TRACE;__MonoCS__ FEATURE_SERIALIZATION</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DocumentationFile>bin\Release\StackExchange.Redis.xml</DocumentationFile>
<Optimize>true</Optimize>
......@@ -75,6 +75,7 @@
<ItemGroup>
<Compile Include="StackExchange\Redis\Aggregate.cs" />
<Compile Include="StackExchange\Redis\ClientType.cs" />
<Compile Include="StackExchange\Redis\Compat\VolatileWrapper.cs" />
<Compile Include="StackExchange\Redis\ConcurrentProfileStorageCollection.cs" />
<Compile Include="StackExchange\Redis\ConnectionMultiplexer.Profiling.cs">
<DependentUpon>ConnectionMultiplexer.cs</DependentUpon>
......@@ -83,6 +84,7 @@
<Compile Include="StackExchange\Redis\HashEntry.cs" />
<Compile Include="StackExchange\Redis\IConnectionMultiplexer.cs" />
<Compile Include="StackExchange\Redis\InternalErrorEventArgs.cs" />
<Compile Include="StackExchange\Redis\InternalRegexCompiledOption.cs" />
<Compile Include="StackExchange\Redis\IProfiler.cs" />
<Compile Include="StackExchange\Redis\MigrateOptions.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()
// give it a moment and try again, noting that we might lose the battle
// when we pause
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?
lock (asyncCompletionQueue)
......@@ -176,5 +176,20 @@ private void ProcessAsyncCompletionQueueImpl()
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
/// <summary>
/// The options relevant to a set of redis connections
/// </summary>
public sealed class ConfigurationOptions : ICloneable
public sealed class ConfigurationOptions
#if !DNXCORE50
: ICloneable
#endif
{
internal const string DefaultTieBreaker = "__Booksleeve_TieBreak", DefaultConfigurationChannel = "__Booksleeve_MasterChanged";
......@@ -84,7 +87,7 @@ internal static void Unknown(string key)
ConfigChannel, AbortOnConnectFail, ResolveDns,
ChannelPrefix, Proxy, ConnectRetry,
ConfigCheckSeconds, DefaultDatabase,
}.ToDictionary(x => x, StringComparer.InvariantCultureIgnoreCase);
}.ToDictionary(x => x, StringComparer.OrdinalIgnoreCase);
public static string TryNormalize(string value)
{
......@@ -139,7 +142,11 @@ public static string TryNormalize(string value)
/// <summary>
/// Indicates whether the connection should be encrypted
/// </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; } }
/// <summary>
......@@ -248,7 +255,7 @@ public CommandMap CommandMap
/// <summary>
/// Specifies the time in milliseconds that the system should allow for synchronous operations (defaults to 1 second)
/// </summary>
public int SyncTimeout { get { return syncTimeout.GetValueOrDefault(1000); } set { syncTimeout = value; } }
public int SyncTimeout { get { return syncTimeout.GetValueOrDefault(20000); } set { syncTimeout = value; } }
/// <summary>
/// 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()
#pragma warning disable 1998 // NET40 is sync, not async, currently
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++)
{
var dns = endpoints[i] as DnsEndPoint;
......@@ -463,10 +470,13 @@ static void Append(StringBuilder sb, string prefix, object value)
}
}
#if !DNXCORE50
static bool IsOption(string option, string prefix)
{
return option.StartsWith(prefix, StringComparison.InvariantCultureIgnoreCase);
}
#endif
void Clear()
{
clientName = serviceName = password = tieBreaker = sslHost = configChannel = null;
......@@ -482,7 +492,9 @@ void Clear()
SocketManager = null;
}
#if !DNXCORE50
object ICloneable.Clone() { return Clone(); }
#endif
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);
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;
}
}
......
......@@ -95,7 +95,7 @@ public ServerCounters GetCounters()
/// <summary>
/// Gets the client-name that will be used on all new connections
/// </summary>
public string ClientName { get { return configuration.ClientName ?? Environment.MachineName; } }
public string ClientName { get { return configuration.ClientName ?? Environment.GetEnvironmentVariable("ComputerName"); } }
/// <summary>
/// Gets the configuration of the connection
......@@ -482,7 +482,7 @@ public EndPoint[] GetEndPoints(bool configuredOnly = false)
{
if (configuredOnly) return configuration.EndPoints.ToArray();
return Array.ConvertAll(serverSnapshot, x => x.EndPoint);
return serverSnapshot.Select(x => x.EndPoint).ToArray();
}
private readonly int timeoutMilliseconds;
......@@ -560,6 +560,8 @@ private static bool WaitAllIgnoreErrors(Task[] tasks, int timeout)
}
return false;
}
#if !DNXCORE50
private void LogLockedWithThreadPoolStats(TextWriter log, string message, out int busyWorkerCount)
{
busyWorkerCount = 0;
......@@ -573,6 +575,8 @@ private void LogLockedWithThreadPoolStats(TextWriter log, string message, out in
LogLocked(log, sb.ToString());
}
}
#endif
static bool AllComplete(Task[] tasks)
{
for(int i = 0 ; i < tasks.Length ; i++)
......@@ -599,16 +603,19 @@ private async Task<bool> WaitAllIgnoreErrorsAsync(Task[] tasks, int timeoutMilli
}
var watch = Stopwatch.StartNew();
#if !DNXCORE50
int busyWorkerCount;
LogLockedWithThreadPoolStats(log, "Awaiting task completion", out busyWorkerCount);
#endif
try
{
// if none error, great
var remaining = timeoutMilliseconds - checked((int)watch.ElapsedMilliseconds);
if (remaining <= 0)
{
#if !DNXCORE50
LogLockedWithThreadPoolStats(log, "Timeout before awaiting for tasks", out busyWorkerCount);
#endif
return false;
}
......@@ -620,7 +627,9 @@ private async Task<bool> WaitAllIgnoreErrorsAsync(Task[] tasks, int timeoutMilli
var any = Task.WhenAny(allTasks, Task.Delay(remaining)).ObserveErrors();
#endif
bool all = await any.ForAwait() == allTasks;
#if !DNXCORE50
LogLockedWithThreadPoolStats(log, all ? "All tasks completed cleanly" : "Not all tasks completed cleanly", out busyWorkerCount);
#endif
return all;
}
catch
......@@ -636,7 +645,9 @@ private async Task<bool> WaitAllIgnoreErrorsAsync(Task[] tasks, int timeoutMilli
var remaining = timeoutMilliseconds - checked((int)watch.ElapsedMilliseconds);
if (remaining <= 0)
{
#if !DNXCORE50
LogLockedWithThreadPoolStats(log, "Timeout awaiting tasks", out busyWorkerCount);
#endif
return false;
}
try
......@@ -652,7 +663,9 @@ private async Task<bool> WaitAllIgnoreErrorsAsync(Task[] tasks, int timeoutMilli
{ }
}
}
#if !DNXCORE50
LogLockedWithThreadPoolStats(log, "Finished awaiting tasks", out busyWorkerCount);
#endif
return false;
}
......@@ -927,12 +940,12 @@ private void OnHeartbeat()
private static int lastGlobalHeartbeatTicks = Environment.TickCount;
internal long LastHeartbeatSecondsAgo {
get {
if (pulse == null) return -1;
return unchecked(Environment.TickCount - Thread.VolatileRead(ref lastHeartbeatTicks)) / 1000;
if (pulse == null) return -1;
return unchecked(Environment.TickCount - VolatileWrapper.Read(ref lastHeartbeatTicks)) / 1000;
}
}
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; } }
......@@ -1434,7 +1447,7 @@ private async Task<ServerEndPoint> NominatePreferredMaster(TextWriter log, Serve
Dictionary<string, int> uniques = null;
if (useTieBreakers)
{ // count the votes
uniques = new Dictionary<string, int>(StringComparer.InvariantCultureIgnoreCase);
uniques = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
await WaitAllIgnoreErrorsAsync(tieBreakers, 50, log).ForAwait();
for (int i = 0; i < tieBreakers.Length; i++)
{
......@@ -1874,8 +1887,7 @@ internal T ExecuteSyncImpl<T>(Message message, ResultProcessor<T> processor, Ser
else
{
int inst, qu, qs, qc, wr, wq, @in, ar;
string iocp, worker;
#if !__MonoCS__
#if FEATURE_SOCKET_MODE_POLL
var mgrState = socketManager.State;
var lastError = socketManager.LastErrorTimeRelative();
......@@ -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 busyWorkerCount = GetThreadPoolStats(out iocp, out worker);
add("Instantaneous", "inst", inst.ToString());
#if !__MonoCS__
#if FEATURE_SOCKET_MODE_POLL
add("Manager-State", "mgr", mgrState.ToString());
add("Last-Error", "err", lastError);
#endif
......@@ -1904,10 +1915,14 @@ internal T ExecuteSyncImpl<T>(Message message, ResultProcessor<T> processor, Ser
add("Inbound-Bytes", "in", @in.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-Workers", "WORKER", worker);
add("Client-Name", "clientName", ClientName);
data.Add(Tuple.Create("Busy-Workers", busyWorkerCount.ToString()));
#endif
errMessage = sb.ToString();
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
Trace(message + " received " + val);
return val;
}
}
}
#if !DNXCORE50
private static int GetThreadPoolStats(out string iocp, out string worker)
{
//BusyThreads = TP.GetMaxThreads() –TP.GetAVailable();
......@@ -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);
return busyWorkerThreads;
}
#endif
/// <summary>
/// Should exceptions include identifiable details? (key names, additional .Data annotations)
......
using System;
using System.Collections.Generic;
namespace StackExchange.Redis
{
/// <summary>
/// Utility methods
/// </summary>
public static class ExtensionMethods
{
/// <summary>
/// Create a dictionary from an array of HashEntry values
/// </summary>
public static Dictionary<string,string> ToStringDictionary(this HashEntry[] hash)
{
if (hash == null) return null;
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);
}
return result;
}
/// <summary>
/// Create a dictionary from an array of HashEntry values
/// </summary>
public static Dictionary<RedisValue, RedisValue> ToDictionary(this HashEntry[] hash)
{
if (hash == null) return null;
var result = new Dictionary<RedisValue, RedisValue>(hash.Length);
for (int i = 0; i < hash.Length; i++)
{
result.Add(hash[i].name, hash[i].value);
}
return result;
}
/// <summary>
/// Create a dictionary from an array of SortedSetEntry values
/// </summary>
public static Dictionary<string, double> ToStringDictionary(this SortedSetEntry[] sortedSet)
{
if (sortedSet == null) return null;
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);
}
return result;
}
/// <summary>
/// Create a dictionary from an array of SortedSetEntry values
/// </summary>
public static Dictionary<RedisValue, double> ToDictionary(this SortedSetEntry[] sortedSet)
{
if (sortedSet == null) return null;
var result = new Dictionary<RedisValue, double>(sortedSet.Length);
for (int i = 0; i < sortedSet.Length; i++)
{
result.Add(sortedSet[i].element, sortedSet[i].score);
}
return result;
}
/// <summary>
/// Create a dictionary from an array of key/value pairs
/// </summary>
public static Dictionary<string, string> ToStringDictionary(this KeyValuePair<RedisKey, RedisValue>[] pairs)
{
if (pairs == null) return null;
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);
}
return result;
}
/// <summary>
/// Create a dictionary from an array of key/value pairs
/// </summary>
public static Dictionary<RedisKey, RedisValue> ToDictionary(this KeyValuePair<RedisKey, RedisValue>[] pairs)
{
if (pairs == null) return null;
var result = new Dictionary<RedisKey, RedisValue>(pairs.Length);
for (int i = 0; i < pairs.Length; i++)
{
result.Add(pairs[i].Key, pairs[i].Value);
}
return result;
}
/// <summary>
/// Create a dictionary from an array of string pairs
/// </summary>
public static Dictionary<string, string> ToDictionary(this KeyValuePair<string, string>[] pairs)
{
if (pairs == null) return null;
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);
}
return result;
}
static readonly string[] nix = new string[0];
/// <summary>
/// Create an array of strings from an array of values
/// </summary>
public static string[] ToStringArray(this RedisValue[] values)
{
if (values == null) return null;
if (values.Length == 0) return nix;
return Array.ConvertAll(values, x => (string)x);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
namespace StackExchange.Redis
{
/// <summary>
/// Utility methods
/// </summary>
public static class ExtensionMethods
{
/// <summary>
/// Create a dictionary from an array of HashEntry values
/// </summary>
public static Dictionary<string,string> ToStringDictionary(this HashEntry[] hash)
{
if (hash == null) return null;
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);
}
return result;
}
/// <summary>
/// Create a dictionary from an array of HashEntry values
/// </summary>
public static Dictionary<RedisValue, RedisValue> ToDictionary(this HashEntry[] hash)
{
if (hash == null) return null;
var result = new Dictionary<RedisValue, RedisValue>(hash.Length);
for (int i = 0; i < hash.Length; i++)
{
result.Add(hash[i].name, hash[i].value);
}
return result;
}
/// <summary>
/// Create a dictionary from an array of SortedSetEntry values
/// </summary>
public static Dictionary<string, double> ToStringDictionary(this SortedSetEntry[] sortedSet)
{
if (sortedSet == null) return null;
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);
}
return result;
}
/// <summary>
/// Create a dictionary from an array of SortedSetEntry values
/// </summary>
public static Dictionary<RedisValue, double> ToDictionary(this SortedSetEntry[] sortedSet)
{
if (sortedSet == null) return null;
var result = new Dictionary<RedisValue, double>(sortedSet.Length);
for (int i = 0; i < sortedSet.Length; i++)
{
result.Add(sortedSet[i].element, sortedSet[i].score);
}
return result;
}
/// <summary>
/// Create a dictionary from an array of key/value pairs
/// </summary>
public static Dictionary<string, string> ToStringDictionary(this KeyValuePair<RedisKey, RedisValue>[] pairs)
{
if (pairs == null) return null;
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);
}
return result;
}
/// <summary>
/// Create a dictionary from an array of key/value pairs
/// </summary>
public static Dictionary<RedisKey, RedisValue> ToDictionary(this KeyValuePair<RedisKey, RedisValue>[] pairs)
{
if (pairs == null) return null;
var result = new Dictionary<RedisKey, RedisValue>(pairs.Length);
for (int i = 0; i < pairs.Length; i++)
{
result.Add(pairs[i].Key, pairs[i].Value);
}
return result;
}
/// <summary>
/// Create a dictionary from an array of string pairs
/// </summary>
public static Dictionary<string, string> ToDictionary(this KeyValuePair<string, string>[] pairs)
{
if (pairs == null) return null;
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);
}
return result;
}
static readonly string[] nix = new string[0];
/// <summary>
/// Create an array of strings from an array of values
/// </summary>
public static string[] ToStringArray(this RedisValue[] values)
{
if (values == null) return null;
if (values.Length == 0) return nix;
return values.Select(x => (string)x).ToArray();
}
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
namespace StackExchange.Redis
{
/// <summary>
/// Describes a hash-field (a name/value pair)
/// </summary>
public struct HashEntry : IEquatable<HashEntry>
{
internal readonly RedisValue name, value;
/// <summary>
/// Initializes a HashEntry value
/// </summary>
public HashEntry(RedisValue name, RedisValue value)
{
this.name = name;
this.value = value;
}
/// <summary>
/// The name of the hash field
/// </summary>
public RedisValue Name { get { return name; } }
/// <summary>
/// The value of the hash field
/// </summary>
public RedisValue Value{ get { return value; } }
/// <summary>
/// The name of the hash field
/// </summary>
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never), Obsolete("Please use Name", false)]
public RedisValue Key { get { return name; } }
/// <summary>
/// Converts to a key/value pair
/// </summary>
public static implicit operator KeyValuePair<RedisValue, RedisValue>(HashEntry value)
{
return new KeyValuePair<RedisValue, RedisValue>(value.name, value.value);
}
/// <summary>
/// Converts from a key/value pair
/// </summary>
public static implicit operator HashEntry(KeyValuePair<RedisValue, RedisValue> value)
{
return new HashEntry(value.Key, value.Value);
}
/// <summary>
/// See Object.ToString()
/// </summary>
public override string ToString()
{
return name + ": " + value;
}
/// <summary>
/// See Object.GetHashCode()
/// </summary>
public override int GetHashCode()
{
return name.GetHashCode() ^ value.GetHashCode();
}
/// <summary>
/// Compares two values for equality
/// </summary>
public override bool Equals(object obj)
{
return obj is HashEntry && Equals((HashEntry)obj);
}
/// <summary>
/// Compares two values for equality
/// </summary>
public bool Equals(HashEntry value)
{
return this.name == value.name && this.value == value.value;
}
/// <summary>
/// Compares two values for equality
/// </summary>
public static bool operator ==(HashEntry x, HashEntry y)
{
return x.name == y.name && x.value == y.value;
}
/// <summary>
/// Compares two values for non-equality
/// </summary>
public static bool operator !=(HashEntry x, HashEntry y)
{
return x.name != y.name || x.value != y.value;
}
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
namespace StackExchange.Redis
{
/// <summary>
/// Describes a hash-field (a name/value pair)
/// </summary>
public struct HashEntry : IEquatable<HashEntry>
{
internal readonly RedisValue name, value;
/// <summary>
/// Initializes a HashEntry value
/// </summary>
public HashEntry(RedisValue name, RedisValue value)
{
this.name = name;
this.value = value;
}
/// <summary>
/// The name of the hash field
/// </summary>
public RedisValue Name { get { return name; } }
/// <summary>
/// The value of the hash field
/// </summary>
public RedisValue Value{ get { return value; } }
/// <summary>
/// The name of the hash field
/// </summary>
#if !DNXCORE50
[Browsable(false)]
#endif
[EditorBrowsable(EditorBrowsableState.Never), Obsolete("Please use Name", false)]
public RedisValue Key { get { return name; } }
/// <summary>
/// Converts to a key/value pair
/// </summary>
public static implicit operator KeyValuePair<RedisValue, RedisValue>(HashEntry value)
{
return new KeyValuePair<RedisValue, RedisValue>(value.name, value.value);
}
/// <summary>
/// Converts from a key/value pair
/// </summary>
public static implicit operator HashEntry(KeyValuePair<RedisValue, RedisValue> value)
{
return new HashEntry(value.Key, value.Value);
}
/// <summary>
/// See Object.ToString()
/// </summary>
public override string ToString()
{
return name + ": " + value;
}
/// <summary>
/// See Object.GetHashCode()
/// </summary>
public override int GetHashCode()
{
return name.GetHashCode() ^ value.GetHashCode();
}
/// <summary>
/// Compares two values for equality
/// </summary>
public override bool Equals(object obj)
{
return obj is HashEntry && Equals((HashEntry)obj);
}
/// <summary>
/// Compares two values for equality
/// </summary>
public bool Equals(HashEntry value)
{
return this.name == value.name && this.value == value.value;
}
/// <summary>
/// Compares two values for equality
/// </summary>
public static bool operator ==(HashEntry x, HashEntry y)
{
return x.name == y.name && x.value == y.value;
}
/// <summary>
/// Compares two values for non-equality
/// </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
{
string missingMember;
string badMemberType;
if(!ScriptParameterMapper.IsValidParameterHash(psType, this, out missingMember, out badMemberType))
if (!ScriptParameterMapper.IsValidParameterHash(psType, this, out missingMember, out badMemberType))
{
if (missingMember != null)
{
......
......@@ -2,7 +2,9 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
#if FEATURE_SERIALIZATION
using System.Runtime.Serialization;
#endif
using System.Text;
using System.Threading.Tasks;
......@@ -11,22 +13,29 @@ namespace StackExchange.Redis
/// <summary>
/// Indicates that a command was illegal and was not sent to the server
/// </summary>
#if FEATURE_SERIALIZATION
[Serializable]
#endif
public sealed class RedisCommandException : Exception
{
#if FEATURE_SERIALIZATION
private RedisCommandException(SerializationInfo info, StreamingContext ctx) : base(info, ctx) { }
#endif
internal RedisCommandException(string message) : base(message) { }
internal RedisCommandException(string message, Exception innerException) : base(message, innerException) { }
}
/// <summary>
/// Indicates a connection fault when communicating with redis
/// </summary>
#if FEATURE_SERIALIZATION
[Serializable]
#endif
public sealed class RedisConnectionException : RedisException
{
#if FEATURE_SERIALIZATION
private RedisConnectionException(SerializationInfo info, StreamingContext ctx) : base(info, ctx)
{
this.FailureType = (ConnectionFailureType)info.GetInt32("failureType");
......@@ -39,6 +48,7 @@ public override void GetObjectData(SerializationInfo info, StreamingContext cont
base.GetObjectData(info, context);
info.AddValue("failureType", (int)this.FailureType);
}
#endif
internal RedisConnectionException(ConnectionFailureType failureType, string message) : base(message)
{
......@@ -54,28 +64,36 @@ internal RedisConnectionException(ConnectionFailureType failureType, string mess
/// </summary>
public ConnectionFailureType FailureType { get; private set; }
}
/// <summary>
/// Indicates an issue communicating with redis
/// </summary>
#if FEATURE_SERIALIZATION
[Serializable]
#endif
public class RedisException : Exception
{
/// <summary>
/// Deserialization constructor; not intended for general usage
/// </summary>
#if FEATURE_SERIALIZATION
protected RedisException(SerializationInfo info, StreamingContext ctx) : base(info, ctx) { }
#endif
internal RedisException(string message) : base(message) { }
internal RedisException(string message, Exception innerException) : base(message, innerException) { }
}
/// <summary>
/// Indicates an exception raised by a redis server
/// </summary>
#if FEATURE_SERIALIZATION
[Serializable]
#endif
public sealed class RedisServerException : RedisException
{
#if FEATURE_SERIALIZATION
private RedisServerException(SerializationInfo info, StreamingContext ctx) : base(info, ctx) { }
#endif
internal RedisServerException(string message) : base(message) { }
}
......
......@@ -394,7 +394,7 @@ internal void OnHeartbeat(bool ifConnectedOnly)
switch (state)
{
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)
{
Trace("Aborting connect");
......
using System;
#if DNXCORE50
using System.Collections.Generic;
using System.Reflection;
#endif
using System.Text;
namespace StackExchange.Redis
......@@ -300,9 +304,14 @@ public int CompareTo(RedisValue other)
{
if (otherType == CompareType.Int64) return thisDouble.CompareTo((double)otherInt64);
if (otherType == CompareType.Double) return thisDouble.CompareTo(otherDouble);
}
// otherwise, compare as strings
}
// otherwise, compare as strings
#if !DNXCORE50
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)
{
......@@ -601,7 +610,7 @@ object IConvertible.ToType(Type conversionType, IFormatProvider provider)
if (conversionType== null) throw new ArgumentNullException("conversionType");
if (conversionType== typeof(byte[])) return (byte[])this;
if (conversionType == typeof(RedisValue)) return this;
switch(Type.GetTypeCode(conversionType))
switch(conversionType.GetTypeCode())
{
case TypeCode.Boolean: return (bool)this;
case TypeCode.Byte: return (byte)this;
......@@ -703,5 +712,49 @@ public bool TryParse(out double 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