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
...@@ -17,3 +17,5 @@ redis-cli.exe ...@@ -17,3 +17,5 @@ redis-cli.exe
Redis Configs/*.dat Redis Configs/*.dat
RedisQFork*.dat RedisQFork*.dat
StackExchange.Redis.*.zip 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 ...@@ -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()
{
Assert.Throws<RedisConnectionException>(() =>
{ {
var log = new StringWriter(); var log = new StringWriter();
try { try {
using (var conn = ConnectionMultiplexer.Connect(Config.LocalHost + ":6500")) { } using (var conn = ConnectionMultiplexer.Connect(Config.LocalHost + ":6500")) { }
} finally { }
finally {
Console.WriteLine(log); Console.WriteLine(log);
} }
});
} }
[Test, ExpectedException(typeof(RedisConnectionException))]
[Test]
public void CanNotOpenNonsenseConnection_DNS() public void CanNotOpenNonsenseConnection_DNS()
{
Assert.Throws<RedisConnectionException>(() =>
{ {
var log = new StringWriter(); var log = new StringWriter();
try { try
{
using (var conn = ConnectionMultiplexer.Connect("doesnot.exist.ds.aasd981230d.com:6500", log)) { } using (var conn = ConnectionMultiplexer.Connect("doesnot.exist.ds.aasd981230d.com:6500", log)) { }
} finally { }
finally
{
Console.WriteLine(log); Console.WriteLine(log);
} }
});
} }
[Test] [Test]
......
...@@ -55,8 +55,10 @@ public void ExecuteWithEmptyStartingPoint() ...@@ -55,8 +55,10 @@ 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()
{
Assert.Throws<RedisConnectionException>(() =>
{ {
using (var muxer = Config.GetUnsecuredConnection()) using (var muxer = Config.GetUnsecuredConnection())
{ {
...@@ -72,11 +74,14 @@ public void ExecuteWithNonHashStartingPoint() ...@@ -72,11 +74,14 @@ public void ExecuteWithNonHashStartingPoint()
{ {
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,8 +264,10 @@ public void NonAsciiScripts() ...@@ -264,8 +264,10 @@ public void NonAsciiScripts()
} }
} }
[Test, ExpectedException(typeof(RedisServerException), ExpectedMessage = "oops")] [Test]
public void ScriptThrowsError() public void ScriptThrowsError()
{
Assert.Throws<RedisServerException>(() =>
{ {
using (var muxer = GetScriptConn()) using (var muxer = GetScriptConn())
{ {
...@@ -274,11 +276,14 @@ public void ScriptThrowsError() ...@@ -274,11 +276,14 @@ public void ScriptThrowsError()
try try
{ {
conn.Wait(result); conn.Wait(result);
} catch(AggregateException ex) }
catch (AggregateException ex)
{ {
throw ex.InnerExceptions[0]; 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
...@@ -2,7 +2,9 @@ ...@@ -2,7 +2,9 @@
using System.Diagnostics; using System.Diagnostics;
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;
using StackExchange.Redis.KeyspaceIsolation; using StackExchange.Redis.KeyspaceIsolation;
namespace StackExchange.Redis.Tests namespace StackExchange.Redis.Tests
...@@ -72,26 +74,28 @@ public void PingMany(bool preserveOrder) ...@@ -72,26 +74,28 @@ public void PingMany(bool preserveOrder)
} }
[Test] [Test]
[ExpectedException(typeof(ArgumentException), ExpectedMessage = @"A null key is not valid in this context")]
public void GetWithNullKey() public void GetWithNullKey()
{ {
using (var muxer = Create()) using (var muxer = Create())
{ {
var db = muxer.GetDatabase(); var db = muxer.GetDatabase();
string key = null; string key = null;
db.StringGet(key); Assert.Throws<ArgumentException>(
() => db.StringGet(key),
"A null key is not valid in this context");
} }
} }
[Test] [Test]
[ExpectedException(typeof(ArgumentException), ExpectedMessage = @"A null key is not valid in this context")]
public void SetWithNullKey() public void SetWithNullKey()
{ {
using (var muxer = Create()) using (var muxer = Create())
{ {
var db = muxer.GetDatabase(); var db = muxer.GetDatabase();
string key = null, value = "abc"; string key = null, value = "abc";
db.StringSet(key, value); Assert.Throws<ArgumentException>(
() => db.StringSet(key, value),
"A null key is not valid in this context");
} }
} }
...@@ -230,9 +234,19 @@ public void MassiveBulkOpsAsync(bool preserveOrder, bool withContinuation) ...@@ -230,9 +234,19 @@ public void MassiveBulkOpsAsync(bool preserveOrder, bool withContinuation)
var conn = muxer.GetDatabase(); var conn = muxer.GetDatabase();
muxer.Wait(conn.PingAsync()); muxer.Wait(conn.PingAsync());
#if DNXCORE50
int number = 0;
#endif
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++)
...@@ -293,7 +307,6 @@ public void GetWithExpiry(bool exists, bool hasExpiry) ...@@ -293,7 +307,6 @@ public void GetWithExpiry(bool exists, bool hasExpiry)
} }
} }
[Test] [Test]
[ExpectedException(typeof(RedisServerException), ExpectedMessage = "WRONGTYPE Operation against a key holding the wrong kind of value")]
public void GetWithExpiryWrongTypeAsync() public void GetWithExpiryWrongTypeAsync()
{ {
using (var conn = Create()) using (var conn = Create())
...@@ -302,21 +315,26 @@ public void GetWithExpiryWrongTypeAsync() ...@@ -302,21 +315,26 @@ public void GetWithExpiryWrongTypeAsync()
RedisKey key = Me(); RedisKey key = Me();
db.KeyDelete(key); db.KeyDelete(key);
db.SetAdd(key, "abc"); db.SetAdd(key, "abc");
Assert.Throws<RedisServerException>(() =>
{
try try
{ {
var async = db.Wait(db.StringGetWithExpiryAsync(key)); var async = db.Wait(db.StringGetWithExpiryAsync(key));
} }
catch(AggregateException ex) catch (AggregateException ex)
{ {
throw ex.InnerExceptions[0]; throw ex.InnerExceptions[0];
} }
Assert.Fail(); Assert.Fail();
},
"A null key is not valid in this context");
} }
} }
[Test] [Test]
[ExpectedException(typeof(RedisServerException), ExpectedMessage = "WRONGTYPE Operation against a key holding the wrong kind of value")]
public void GetWithExpiryWrongTypeSync() public void GetWithExpiryWrongTypeSync()
{
Assert.Throws<RedisServerException>(() =>
{ {
using (var conn = Create()) using (var conn = Create())
{ {
...@@ -327,8 +345,11 @@ public void GetWithExpiryWrongTypeSync() ...@@ -327,8 +345,11 @@ public void GetWithExpiryWrongTypeSync()
db.StringGetWithExpiry(key); db.StringGetWithExpiry(key);
Assert.Fail(); Assert.Fail();
} }
},
"WRONGTYPE Operation against a key holding the wrong kind of value");
} }
#if FEATURE_BOOKSLEEVE
[Test] [Test]
[TestCase(true, true, ResultCompletionMode.ConcurrentIfContinuation)] [TestCase(true, true, ResultCompletionMode.ConcurrentIfContinuation)]
[TestCase(true, false, ResultCompletionMode.ConcurrentIfContinuation)] [TestCase(true, false, ResultCompletionMode.ConcurrentIfContinuation)]
...@@ -378,7 +399,7 @@ public void MassiveBulkOpsAsyncOldStyle(bool withContinuation, bool suspendFlush ...@@ -378,7 +399,7 @@ public void MassiveBulkOpsAsyncOldStyle(bool withContinuation, bool suspendFlush
completionMode, AsyncOpsQty / watch.Elapsed.TotalSeconds); completionMode, AsyncOpsQty / watch.Elapsed.TotalSeconds);
} }
} }
#endif
[Test] [Test]
[TestCase(true, 1)] [TestCase(true, 1)]
...@@ -423,6 +444,8 @@ public void MassiveBulkOpsSync(bool preserveOrder, int threads) ...@@ -423,6 +444,8 @@ public void MassiveBulkOpsSync(bool preserveOrder, int threads)
#endif #endif
} }
} }
#if FEATURE_BOOKSLEEVE
[Test] [Test]
[TestCase(ResultCompletionMode.Concurrent, 1)] [TestCase(ResultCompletionMode.Concurrent, 1)]
[TestCase(ResultCompletionMode.ConcurrentIfContinuation, 1)] [TestCase(ResultCompletionMode.ConcurrentIfContinuation, 1)]
...@@ -462,6 +485,7 @@ public void MassiveBulkOpsSyncOldStyle(ResultCompletionMode completionMode, int ...@@ -462,6 +485,7 @@ public void MassiveBulkOpsSyncOldStyle(ResultCompletionMode completionMode, int
completionMode, threads, (workPerThread * threads) / timeTaken.TotalSeconds); completionMode, threads, (workPerThread * threads) / timeTaken.TotalSeconds);
} }
} }
#endif
[Test] [Test]
[TestCase(true, 1)] [TestCase(true, 1)]
......
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
...@@ -20,7 +20,11 @@ public class Cluster : TestBase ...@@ -20,7 +20,11 @@ public class Cluster : TestBase
protected override string GetConfiguration() protected override string GetConfiguration()
{ {
var server = ClusterIp; var server = ClusterIp;
#if !DNXCORE50
if (string.Equals(Environment.MachineName, "MARC-LAPTOP", StringComparison.InvariantCultureIgnoreCase)) if (string.Equals(Environment.MachineName, "MARC-LAPTOP", StringComparison.InvariantCultureIgnoreCase))
#else
if (string.Equals(Environment.GetEnvironmentVariable("COMPUTERNAME"), "MARC-LAPTOP", StringComparison.OrdinalIgnoreCase))
#endif
{ {
server = "192.168.56.101"; server = "192.168.56.101";
} }
...@@ -130,7 +134,7 @@ public void IntentionalWrongServer() ...@@ -130,7 +134,7 @@ public void IntentionalWrongServer()
using (var conn = Create()) using (var conn = Create())
{ {
var endpoints = conn.GetEndPoints(); var endpoints = conn.GetEndPoints();
var servers = Array.ConvertAll(endpoints, e => conn.GetServer(e)); var servers = endpoints.Select(e => conn.GetServer(e));
var key = Me(); var key = Me();
const string value = "abc"; const string value = "abc";
...@@ -198,10 +202,11 @@ public void IntentionalWrongServer() ...@@ -198,10 +202,11 @@ public void IntentionalWrongServer()
} }
[Test] [Test]
[ExpectedException(typeof(RedisCommandException), ExpectedMessage = "Multi-key operations must involve a single slot; keys can use 'hash tags' to help this, i.e. '{/users/12345}/account' and '{/users/12345}/contacts' will always be in the same slot")]
public void TransactionWithMultiServerKeys() public void TransactionWithMultiServerKeys()
{ {
using(var muxer = Create()) Assert.Throws<RedisCommandException>(() =>
{
using (var muxer = Create())
{ {
// connect // connect
var cluster = muxer.GetDatabase(); var cluster = muxer.GetDatabase();
...@@ -249,11 +254,14 @@ public void TransactionWithMultiServerKeys() ...@@ -249,11 +254,14 @@ public void TransactionWithMultiServerKeys()
//Assert.IsFalse(cluster.Wait(existsX), "x exists"); //Assert.IsFalse(cluster.Wait(existsX), "x exists");
//Assert.IsFalse(cluster.Wait(existsY), "y exists"); //Assert.IsFalse(cluster.Wait(existsY), "y exists");
} }
},
"Multi-key operations must involve a single slot; keys can use 'hash tags' to help this, i.e. '{/users/12345}/account' and '{/users/12345}/contacts' will always be in the same slot");
} }
[Test] [Test]
[ExpectedException(typeof(RedisCommandException), ExpectedMessage = "Multi-key operations must involve a single slot; keys can use 'hash tags' to help this, i.e. '{/users/12345}/account' and '{/users/12345}/contacts' will always be in the same slot")]
public void TransactionWithSameServerKeys() public void TransactionWithSameServerKeys()
{
Assert.Throws<RedisCommandException>(() =>
{ {
using (var muxer = Create()) using (var muxer = Create())
{ {
...@@ -302,6 +310,8 @@ public void TransactionWithSameServerKeys() ...@@ -302,6 +310,8 @@ public void TransactionWithSameServerKeys()
//Assert.IsTrue(cluster.Wait(existsX), "x exists"); //Assert.IsTrue(cluster.Wait(existsX), "x exists");
//Assert.IsTrue(cluster.Wait(existsY), "y exists"); //Assert.IsTrue(cluster.Wait(existsY), "y exists");
} }
},
"Multi-key operations must involve a single slot; keys can use 'hash tags' to help this, i.e. '{/users/12345}/account' and '{/users/12345}/contacts' will always be in the same slot");
} }
[Test] [Test]
...@@ -361,7 +371,7 @@ public void Keys(string pattern, int pageSize) ...@@ -361,7 +371,7 @@ public void Keys(string pattern, int pageSize)
using (var conn = Create(allowAdmin: true)) using (var conn = Create(allowAdmin: true))
{ {
var cluster = conn.GetDatabase(); var cluster = conn.GetDatabase();
var server = Array.ConvertAll(conn.GetEndPoints(), x => conn.GetServer(x)).First(x => !x.IsSlave); var server = conn.GetEndPoints().Select(x => conn.GetServer(x)).First(x => !x.IsSlave);
server.FlushAllDatabases(); server.FlushAllDatabases();
try try
{ {
...@@ -467,7 +477,7 @@ public void AccessRandomKeys() ...@@ -467,7 +477,7 @@ public void AccessRandomKeys()
Task[] send = new Task[COUNT]; Task[] send = new Task[COUNT];
int index = 0; int index = 0;
var servers = Array.ConvertAll(conn.GetEndPoints(), x => conn.GetServer(x)); var servers = conn.GetEndPoints().Select(x => conn.GetServer(x));
foreach (var server in servers) foreach (var server in servers)
{ {
if (!server.IsSlave) if (!server.IsSlave)
...@@ -593,7 +603,7 @@ public void MovedProfiling() ...@@ -593,7 +603,7 @@ public void MovedProfiling()
conn.RegisterProfiler(profiler); conn.RegisterProfiler(profiler);
var endpoints = conn.GetEndPoints(); var endpoints = conn.GetEndPoints();
var servers = Array.ConvertAll(endpoints, e => conn.GetServer(e)); var servers = endpoints.Select(e => conn.GetServer(e));
conn.BeginProfiling(profiler.MyContext); conn.BeginProfiling(profiler.MyContext);
var db = conn.GetDatabase(); var db = conn.GetDatabase();
......
...@@ -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);
Assert.Throws<RedisCommandException>(() =>
{
var all = conn.ConfigGet(); 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()
{ {
Assert.Throws<ArgumentException>(() => {
var options = ConfigurationOptions.Parse("ssl2=true", false); 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()
{ {
Assert.Throws<ArgumentException>(() => {
var options = ConfigurationOptions.Parse("ssl2=true"); 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()
{ {
Assert.Throws<RedisCommandException>(() => {
ConfigurationOptions config = GetMasterSlaveConfig(); ConfigurationOptions config = GetMasterSlaveConfig();
using (var conn = ConnectionMultiplexer.Connect(config)) using (var conn = ConnectionMultiplexer.Connect(config))
{ {
var servers = Array.ConvertAll(conn.GetEndPoints(), e => conn.GetServer(e)); var servers = conn.GetEndPoints().Select(e => conn.GetServer(e));
var slave = servers.First(x => x.IsSlave); var slave = servers.First(x => x.IsSlave);
slave.FlushDatabase(); 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)
{ {
Assert.Throws<RedisConnectionException>(() => {
SetExpectedAmbientFailureCount(-1); SetExpectedAmbientFailureCount(-1);
using (var server = Create(password: password, checkConnect: false)) 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
...@@ -28,34 +28,42 @@ public void BlankPrefixYieldsSame_String() ...@@ -28,34 +28,42 @@ public void BlankPrefixYieldsSame_String()
Assert.AreSame(raw, prefixed); Assert.AreSame(raw, prefixed);
} }
} }
[Test, ExpectedException(typeof(ArgumentNullException))] [Test]
public void NullPrefixIsError_Bytes() public void NullPrefixIsError_Bytes()
{ {
Assert.Throws<ArgumentNullException>(() => {
using (var conn = Create()) using (var conn = Create())
{ {
var raw = conn.GetDatabase(1); var raw = conn.GetDatabase(1);
var prefixed = raw.WithKeyPrefix((byte[])null); var prefixed = raw.WithKeyPrefix((byte[])null);
} }
});
} }
[Test, ExpectedException(typeof(ArgumentNullException))]
[Test]
public void NullPrefixIsError_String() public void NullPrefixIsError_String()
{ {
Assert.Throws<ArgumentNullException>(() => {
using (var conn = Create()) using (var conn = Create())
{ {
var raw = conn.GetDatabase(1); var raw = conn.GetDatabase(1);
var prefixed = raw.WithKeyPrefix((string)null); var prefixed = raw.WithKeyPrefix((string)null);
} }
});
} }
[Test, ExpectedException(typeof(ArgumentNullException))] [Test]
[TestCase("abc")] [TestCase("abc")]
[TestCase("")] [TestCase("")]
[TestCase(null)] [TestCase(null)]
public void NullDatabaseIsError(string prefix) public void NullDatabaseIsError(string prefix)
{ {
Assert.Throws<ArgumentNullException>(() => {
IDatabase raw = null; IDatabase raw = null;
var prefixed = raw.WithKeyPrefix(prefix); var prefixed = raw.WithKeyPrefix(prefix);
});
} }
[Test] [Test]
public void BasicSmokeTest() public void BasicSmokeTest()
{ {
......
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()
{ {
Assert.Throws<NotSupportedException>(() => {
wrapper.KeyRandomAsync(); 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.snk\Debug\</OutputPath> <OutputPath>bin.snk\Debug\</OutputPath>
<DefineConstants>TRACE;DEBUG;STRONG_NAME</DefineConstants> <DefineConstants>TRACE;DEBUG;STRONG_NAME 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.snk\Release\</OutputPath> <OutputPath>bin.snk\Release\</OutputPath>
<DefineConstants>TRACE;STRONG_NAME</DefineConstants> <DefineConstants>TRACE;STRONG_NAME 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.snk\Verbose\</OutputPath> <OutputPath>bin.snk\Verbose\</OutputPath>
<DefineConstants>TRACE;DEBUG;VERBOSE STRONG_NAME</DefineConstants> <DefineConstants>TRACE;DEBUG;VERBOSE STRONG_NAME FEATURE_SERIALIZATION FEATURE_SOCKET_MODE_POLL</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DocumentationFile>bin.snk\Verbose\StackExchange.Redis.StrongName.xml</DocumentationFile> <DocumentationFile>bin.snk\Verbose\StackExchange.Redis.StrongName.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.snk\LogOutput\</OutputPath> <OutputPath>bin.snk\LogOutput\</OutputPath>
<DefineConstants>TRACE;DEBUG;LOGOUTPUT STRONG_NAME</DefineConstants> <DefineConstants>TRACE;DEBUG;LOGOUTPUT STRONG_NAME FEATURE_SERIALIZATION FEATURE_SOCKET_MODE_POLL</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DocumentationFile>bin.snk\LogOutput\StackExchange.Redis.StrongName.xml</DocumentationFile> <DocumentationFile>bin.snk\LogOutput\StackExchange.Redis.StrongName.xml</DocumentationFile>
<DebugType>full</DebugType> <DebugType>full</DebugType>
...@@ -64,7 +64,7 @@ ...@@ -64,7 +64,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;STRONG_NAME</DefineConstants> <DefineConstants>TRACE;STRONG_NAME FEATURE_SERIALIZATION</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DocumentationFile>bin.snk\Release\StackExchange.Redis.StrongName.xml</DocumentationFile> <DocumentationFile>bin.snk\Release\StackExchange.Redis.StrongName.xml</DocumentationFile>
<Optimize>true</Optimize> <Optimize>true</Optimize>
...@@ -81,6 +81,7 @@ ...@@ -81,6 +81,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>
...@@ -89,6 +90,7 @@ ...@@ -89,6 +90,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" />
......
...@@ -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" />
......
...@@ -85,8 +85,7 @@ public static CommandMap Create(Dictionary<string, string> overrides) ...@@ -85,8 +85,7 @@ public static CommandMap Create(Dictionary<string, string> overrides)
{ {
if (overrides == null || overrides.Count == 0) return Default; if (overrides == null || overrides.Count == 0) return Default;
if (ReferenceEquals(overrides.Comparer, StringComparer.OrdinalIgnoreCase) || if (ReferenceEquals(overrides.Comparer, StringComparer.OrdinalIgnoreCase))
ReferenceEquals(overrides.Comparer, StringComparer.InvariantCultureIgnoreCase))
{ {
// that's ok; we're happy with ordinal/invariant case-insensitive // that's ok; we're happy with ordinal/invariant case-insensitive
// (but not culture-specific insensitive; completely untested) // (but not culture-specific insensitive; completely untested)
......
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;
} }
...@@ -928,11 +941,11 @@ private void OnHeartbeat() ...@@ -928,11 +941,11 @@ private void OnHeartbeat()
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)
{ {
...@@ -1937,6 +1952,8 @@ internal T ExecuteSyncImpl<T>(Message message, ResultProcessor<T> processor, Ser ...@@ -1937,6 +1952,8 @@ internal T ExecuteSyncImpl<T>(Message message, ResultProcessor<T> processor, Ser
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
{ {
...@@ -120,7 +121,7 @@ public static string[] ToStringArray(this RedisValue[] values) ...@@ -120,7 +121,7 @@ public static string[] ToStringArray(this RedisValue[] values)
{ {
if (values == null) return null; if (values == null) return null;
if (values.Length == 0) return nix; if (values.Length == 0) return nix;
return Array.ConvertAll(values, x => (string)x); return values.Select(x => (string)x).ToArray();
} }
} }
} }
...@@ -31,7 +31,10 @@ public HashEntry(RedisValue name, RedisValue value) ...@@ -31,7 +31,10 @@ public HashEntry(RedisValue name, RedisValue 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
[Browsable(false)]
#endif
[EditorBrowsable(EditorBrowsableState.Never), Obsolete("Please use Name", false)]
public RedisValue Key { get { return name; } } public RedisValue Key { get { return name; } }
/// <summary> /// <summary>
......
#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,10 +13,14 @@ namespace StackExchange.Redis ...@@ -11,10 +13,14 @@ 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) { }
} }
...@@ -24,9 +30,12 @@ public sealed class RedisCommandException : Exception ...@@ -24,9 +30,12 @@ public sealed class RedisCommandException : Exception
/// <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)
{ {
...@@ -58,13 +68,17 @@ internal RedisConnectionException(ConnectionFailureType failureType, string mess ...@@ -58,13 +68,17 @@ internal RedisConnectionException(ConnectionFailureType failureType, string mess
/// <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) { }
...@@ -72,10 +86,14 @@ public class RedisException : Exception ...@@ -72,10 +86,14 @@ public class RedisException : Exception
/// <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");
......
...@@ -10,6 +10,9 @@ ...@@ -10,6 +10,9 @@
using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.X509Certificates;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
#if DNXCORE50
using System.Threading.Tasks;
#endif
namespace StackExchange.Redis namespace StackExchange.Redis
{ {
...@@ -93,7 +96,7 @@ public PhysicalConnection(PhysicalBridge bridge) ...@@ -93,7 +96,7 @@ public PhysicalConnection(PhysicalBridge bridge)
public void BeginConnect(TextWriter log) public void BeginConnect(TextWriter log)
{ {
Thread.VolatileWrite(ref firstUnansweredWriteTickCount, 0); VolatileWrapper.Write(ref firstUnansweredWriteTickCount, 0);
var endpoint = this.bridge.ServerEndPoint.EndPoint; var endpoint = this.bridge.ServerEndPoint.EndPoint;
multiplexer.Trace("Connecting...", physicalName); multiplexer.Trace("Connecting...", physicalName);
...@@ -113,7 +116,7 @@ public long LastWriteSecondsAgo ...@@ -113,7 +116,7 @@ public long LastWriteSecondsAgo
{ {
get get
{ {
return unchecked(Environment.TickCount - Thread.VolatileRead(ref lastWriteTickCount)) / 1000; return unchecked(Environment.TickCount - VolatileWrapper.Read(ref lastWriteTickCount)) / 1000;
} }
} }
...@@ -128,13 +131,17 @@ public void Dispose() ...@@ -128,13 +131,17 @@ public void Dispose()
if (outStream != null) if (outStream != null)
{ {
multiplexer.Trace("Disconnecting...", physicalName); multiplexer.Trace("Disconnecting...", physicalName);
#if !DNXCORE50
try { outStream.Close(); } catch { } try { outStream.Close(); } catch { }
#endif
try { outStream.Dispose(); } catch { } try { outStream.Dispose(); } catch { }
outStream = null; outStream = null;
} }
if (netStream != null) if (netStream != null)
{ {
#if !DNXCORE50
try { netStream.Close(); } catch { } try { netStream.Close(); } catch { }
#endif
try { netStream.Dispose(); } catch { } try { netStream.Dispose(); } catch { }
netStream = null; netStream = null;
} }
...@@ -189,9 +196,9 @@ public void RecordConnectionFailed(ConnectionFailureType failureType, ref Socket ...@@ -189,9 +196,9 @@ public void RecordConnectionFailed(ConnectionFailureType failureType, ref Socket
if (isCurrent && Interlocked.CompareExchange(ref failureReported, 1, 0) == 0) if (isCurrent && Interlocked.CompareExchange(ref failureReported, 1, 0) == 0)
{ {
managerState = SocketManager.ManagerState.RecordConnectionFailed_ReportFailure; managerState = SocketManager.ManagerState.RecordConnectionFailed_ReportFailure;
int now = Environment.TickCount, lastRead = Thread.VolatileRead(ref lastReadTickCount), lastWrite = Thread.VolatileRead(ref lastWriteTickCount), int now = Environment.TickCount, lastRead = VolatileWrapper.Read(ref lastReadTickCount), lastWrite = VolatileWrapper.Read(ref lastWriteTickCount),
lastBeat = Thread.VolatileRead(ref lastBeatTickCount); lastBeat = VolatileWrapper.Read(ref lastBeatTickCount);
int unansweredRead = Thread.VolatileRead(ref firstUnansweredWriteTickCount); int unansweredRead = VolatileWrapper.Read(ref firstUnansweredWriteTickCount);
var exMessage = new StringBuilder(failureType + " on " + Format.ToString(bridge.ServerEndPoint.EndPoint) + "/" + connectionType); var exMessage = new StringBuilder(failureType + " on " + Format.ToString(bridge.ServerEndPoint.EndPoint) + "/" + connectionType);
var data = new List<Tuple<string, string>> var data = new List<Tuple<string, string>>
...@@ -224,7 +231,7 @@ public void RecordConnectionFailed(ConnectionFailureType failureType, ref Socket ...@@ -224,7 +231,7 @@ public void RecordConnectionFailed(ConnectionFailureType failureType, ref Socket
add("Last-Heartbeat", "last-heartbeat", (lastBeat == 0 ? "never" : (unchecked(now - lastBeat)/1000 + "s ago"))+ (bridge.IsBeating ? " (mid-beat)" : "") ); add("Last-Heartbeat", "last-heartbeat", (lastBeat == 0 ? "never" : (unchecked(now - lastBeat)/1000 + "s ago"))+ (bridge.IsBeating ? " (mid-beat)" : "") );
add("Last-Multiplexer-Heartbeat", "last-mbeat", multiplexer.LastHeartbeatSecondsAgo + "s ago"); add("Last-Multiplexer-Heartbeat", "last-mbeat", multiplexer.LastHeartbeatSecondsAgo + "s ago");
add("Last-Global-Heartbeat", "global", ConnectionMultiplexer.LastGlobalHeartbeatSecondsAgo + "s ago"); add("Last-Global-Heartbeat", "global", ConnectionMultiplexer.LastGlobalHeartbeatSecondsAgo + "s ago");
#if !__MonoCS__ #if FEATURE_SOCKET_MODE_POLL
var mgr = bridge.Multiplexer.SocketManager; var mgr = bridge.Multiplexer.SocketManager;
add("SocketManager-State", "mgr", mgr.State.ToString()); add("SocketManager-State", "mgr", mgr.State.ToString());
add("Last-Error", "err", mgr.LastErrorTimeRelative()); add("Last-Error", "err", mgr.LastErrorTimeRelative());
...@@ -595,23 +602,20 @@ unsafe void WriteRaw(Stream stream, string value, int encodedLength) ...@@ -595,23 +602,20 @@ unsafe void WriteRaw(Stream stream, string value, int encodedLength)
stream.Write(outScratch, 0, bytes); stream.Write(outScratch, 0, bytes);
} }
else else
{
fixed (char* c = value)
fixed (byte* b = outScratch)
{ {
int charsRemaining = value.Length, charOffset = 0, bytesWritten; int charsRemaining = value.Length, charOffset = 0, bytesWritten;
var valueCharArray = value.ToCharArray();
while (charsRemaining > Scratch_CharsPerBlock) while (charsRemaining > Scratch_CharsPerBlock)
{ {
bytesWritten = outEncoder.GetBytes(c + charOffset, Scratch_CharsPerBlock, b, ScratchSize, false); bytesWritten = outEncoder.GetBytes(valueCharArray, charOffset, Scratch_CharsPerBlock, outScratch, 0, false);
stream.Write(outScratch, 0, bytesWritten); stream.Write(outScratch, 0, bytesWritten);
charOffset += Scratch_CharsPerBlock; charOffset += Scratch_CharsPerBlock;
charsRemaining -= Scratch_CharsPerBlock; charsRemaining -= Scratch_CharsPerBlock;
} }
bytesWritten = outEncoder.GetBytes(c + charOffset, charsRemaining, b, ScratchSize, true); bytesWritten = outEncoder.GetBytes(valueCharArray, charOffset, charsRemaining, outScratch, 0, true);
if (bytesWritten != 0) stream.Write(outScratch, 0, bytesWritten); if (bytesWritten != 0) stream.Write(outScratch, 0, bytesWritten);
} }
} }
}
const int ScratchSize = 512; const int ScratchSize = 512;
static readonly int Scratch_CharsPerBlock = ScratchSize / Encoding.UTF8.GetMaxByteCount(1); static readonly int Scratch_CharsPerBlock = ScratchSize / Encoding.UTF8.GetMaxByteCount(1);
private readonly byte[] outScratch = new byte[ScratchSize]; private readonly byte[] outScratch = new byte[ScratchSize];
...@@ -657,6 +661,14 @@ void BeginReading() ...@@ -657,6 +661,14 @@ void BeginReading()
int space = EnsureSpaceAndComputeBytesToRead(); int space = EnsureSpaceAndComputeBytesToRead();
multiplexer.Trace("Beginning async read...", physicalName); multiplexer.Trace("Beginning async read...", physicalName);
var result = netStream.BeginRead(ioBuffer, ioBufferBytes, space, endRead, this); var result = netStream.BeginRead(ioBuffer, ioBufferBytes, space, endRead, this);
#if DNXCORE50
Task<int> t = (Task<int>)result;
if (t.Status == TaskStatus.RanToCompletion && t.Result == -1)
{
multiplexer.Trace("Could not connect: ", physicalName);
return;
}
#endif
if (result.CompletedSynchronously) if (result.CompletedSynchronously)
{ {
multiplexer.Trace("Completed synchronously: processing immediately", physicalName); multiplexer.Trace("Completed synchronously: processing immediately", physicalName);
...@@ -664,7 +676,13 @@ void BeginReading() ...@@ -664,7 +676,13 @@ void BeginReading()
} }
} while (keepReading); } while (keepReading);
} }
catch(System.IO.IOException ex) #if DNXCORE50
catch (AggregateException ex)
{
throw ex.InnerException;
}
#endif
catch (System.IO.IOException ex)
{ {
multiplexer.Trace("Could not connect: " + ex.Message, physicalName); multiplexer.Trace("Could not connect: " + ex.Message, physicalName);
} }
...@@ -724,8 +742,11 @@ SocketMode ISocketCallback.Connected(Stream stream, TextWriter log) ...@@ -724,8 +742,11 @@ SocketMode ISocketCallback.Connected(Stream stream, TextWriter log)
, EncryptionPolicy.RequireEncryption , EncryptionPolicy.RequireEncryption
#endif #endif
); );
try
{
ssl.AuthenticateAsClient(host); ssl.AuthenticateAsClient(host);
if (!ssl.IsEncrypted) }
catch (AuthenticationException)
{ {
RecordConnectionFailed(ConnectionFailureType.AuthenticationFailure); RecordConnectionFailed(ConnectionFailureType.AuthenticationFailure);
multiplexer.Trace("Encryption failure"); multiplexer.Trace("Encryption failure");
...@@ -738,7 +759,11 @@ SocketMode ISocketCallback.Connected(Stream stream, TextWriter log) ...@@ -738,7 +759,11 @@ SocketMode ISocketCallback.Connected(Stream stream, TextWriter log)
int bufferSize = config.WriteBuffer; int bufferSize = config.WriteBuffer;
this.netStream = stream; this.netStream = stream;
#if !DNXCORE50
this.outStream = bufferSize <= 0 ? stream : new BufferedStream(stream, bufferSize); this.outStream = bufferSize <= 0 ? stream : new BufferedStream(stream, bufferSize);
#else
this.outStream = stream;
#endif
multiplexer.LogLocked(log, "Connected {0}", bridge); multiplexer.LogLocked(log, "Connected {0}", bridge);
bridge.OnConnected(this, log); bridge.OnConnected(this, log);
...@@ -895,7 +920,7 @@ private bool ProcessReadBytes(int bytesRead) ...@@ -895,7 +920,7 @@ private bool ProcessReadBytes(int bytesRead)
Interlocked.Exchange(ref lastReadTickCount, Environment.TickCount); Interlocked.Exchange(ref lastReadTickCount, Environment.TickCount);
// reset unanswered write timestamp // reset unanswered write timestamp
Thread.VolatileWrite(ref firstUnansweredWriteTickCount, 0); VolatileWrapper.Write(ref firstUnansweredWriteTickCount, 0);
ioBufferBytes += bytesRead; ioBufferBytes += bytesRead;
multiplexer.Trace("More bytes available: " + bytesRead + " (" + ioBufferBytes + ")", physicalName); multiplexer.Trace("More bytes available: " + bytesRead + " (" + ioBufferBytes + ")", physicalName);
...@@ -1058,7 +1083,7 @@ RawResult TryParseResult(byte[] buffer, ref int offset, ref int count) ...@@ -1058,7 +1083,7 @@ RawResult TryParseResult(byte[] buffer, ref int offset, ref int count)
public void CheckForStaleConnection(ref SocketManager.ManagerState managerState) public void CheckForStaleConnection(ref SocketManager.ManagerState managerState)
{ {
int firstUnansweredWrite; int firstUnansweredWrite;
firstUnansweredWrite = Thread.VolatileRead(ref firstUnansweredWriteTickCount); firstUnansweredWrite = VolatileWrapper.Read(ref firstUnansweredWriteTickCount);
DebugEmulateStaleConnection(ref firstUnansweredWrite); DebugEmulateStaleConnection(ref firstUnansweredWrite);
...@@ -1070,4 +1095,38 @@ public void CheckForStaleConnection(ref SocketManager.ManagerState managerState) ...@@ -1070,4 +1095,38 @@ public void CheckForStaleConnection(ref SocketManager.ManagerState managerState)
} }
} }
} }
#if DNXCORE50
internal static class StreamExtensions
{
internal static IAsyncResult BeginRead(this Stream stream, byte[] buffer, int offset, int count, AsyncCallback ac, object state)
{
Task<int> f = Task<int>.Factory.StartNew(_ => {
try
{
return stream.Read(buffer, offset, count);
}
catch (IOException ex)
{
System.Diagnostics.Trace.WriteLine("Could not connect: " + ex.InnerException.Message);
return -1;
}
}, state);
if (ac != null) f.ContinueWith(res => ac(f));
return f;
}
internal static int EndRead(this Stream stream, IAsyncResult ar)
{
try
{
return ((Task<int>)ar).Result;
}
catch (AggregateException ex)
{
throw ex.InnerException;
}
}
}
#endif
} }
using System; using System;
using System.Linq;
namespace StackExchange.Redis namespace StackExchange.Redis
{ {
...@@ -194,14 +195,14 @@ internal override bool AsBoolean() ...@@ -194,14 +195,14 @@ internal override bool AsBoolean()
throw new InvalidCastException(); throw new InvalidCastException();
} }
internal override bool[] AsBooleanArray() { return Array.ConvertAll(value, x => x.AsBoolean()); } internal override bool[] AsBooleanArray() { return value.Select(x => x.AsBoolean()).ToArray(); }
internal override byte[] AsByteArray() internal override byte[] AsByteArray()
{ {
if (value.Length == 1) return value[0].AsByteArray(); if (value.Length == 1) return value[0].AsByteArray();
throw new InvalidCastException(); throw new InvalidCastException();
} }
internal override byte[][] AsByteArrayArray() { return Array.ConvertAll(value, x => x.AsByteArray()); } internal override byte[][] AsByteArrayArray() { return value.Select(x => x.AsByteArray()).ToArray(); }
internal override double AsDouble() internal override double AsDouble()
{ {
...@@ -209,7 +210,7 @@ internal override double AsDouble() ...@@ -209,7 +210,7 @@ internal override double AsDouble()
throw new InvalidCastException(); throw new InvalidCastException();
} }
internal override double[] AsDoubleArray() { return Array.ConvertAll(value, x => x.AsDouble()); } internal override double[] AsDoubleArray() { return value.Select(x => x.AsDouble()).ToArray(); }
internal override int AsInt32() internal override int AsInt32()
{ {
...@@ -217,7 +218,7 @@ internal override int AsInt32() ...@@ -217,7 +218,7 @@ internal override int AsInt32()
throw new InvalidCastException(); throw new InvalidCastException();
} }
internal override int[] AsInt32Array() { return Array.ConvertAll(value, x => x.AsInt32()); } internal override int[] AsInt32Array() { return value.Select(x => x.AsInt32()).ToArray(); }
internal override long AsInt64() internal override long AsInt64()
{ {
...@@ -225,7 +226,7 @@ internal override long AsInt64() ...@@ -225,7 +226,7 @@ internal override long AsInt64()
throw new InvalidCastException(); throw new InvalidCastException();
} }
internal override long[] AsInt64Array() { return Array.ConvertAll(value, x => x.AsInt64()); } internal override long[] AsInt64Array() { return value.Select(x => x.AsInt64()).ToArray(); }
internal override bool? AsNullableBoolean() internal override bool? AsNullableBoolean()
{ {
...@@ -257,7 +258,7 @@ internal override RedisKey AsRedisKey() ...@@ -257,7 +258,7 @@ internal override RedisKey AsRedisKey()
throw new InvalidCastException(); throw new InvalidCastException();
} }
internal override RedisKey[] AsRedisKeyArray() { return Array.ConvertAll(value, x => x.AsRedisKey()); } internal override RedisKey[] AsRedisKeyArray() { return value.Select(x => x.AsRedisKey()).ToArray(); }
internal override RedisResult[] AsRedisResultArray() { return value; } internal override RedisResult[] AsRedisResultArray() { return value; }
...@@ -267,14 +268,14 @@ internal override RedisValue AsRedisValue() ...@@ -267,14 +268,14 @@ internal override RedisValue AsRedisValue()
throw new InvalidCastException(); throw new InvalidCastException();
} }
internal override RedisValue[] AsRedisValueArray() { return Array.ConvertAll(value, x => x.AsRedisValue()); } internal override RedisValue[] AsRedisValueArray() { return value.Select(x => x.AsRedisValue()).ToArray(); }
internal override string AsString() internal override string AsString()
{ {
if (value.Length == 1) return value[0].AsString(); if (value.Length == 1) return value[0].AsString();
throw new InvalidCastException(); throw new InvalidCastException();
} }
internal override string[] AsStringArray() { return Array.ConvertAll(value, x => x.AsString()); } internal override string[] AsStringArray() { return value.Select(x => x.AsString()).ToArray(); }
} }
private sealed class ErrorRedisResult : RedisResult private sealed class ErrorRedisResult : RedisResult
......
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
...@@ -302,7 +306,12 @@ public int CompareTo(RedisValue other) ...@@ -302,7 +306,12 @@ public int CompareTo(RedisValue other)
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;
...@@ -704,4 +713,48 @@ public bool TryParse(out double val) ...@@ -704,4 +713,48 @@ 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
}
} }
...@@ -347,7 +347,7 @@ protected override bool SetResultCore(PhysicalConnection connection, Message mes ...@@ -347,7 +347,7 @@ protected override bool SetResultCore(PhysicalConnection connection, Message mes
internal sealed class ScriptLoadProcessor : ResultProcessor<byte[]> internal sealed class ScriptLoadProcessor : ResultProcessor<byte[]>
{ {
static readonly Regex sha1 = new Regex("^[0-9a-f]{40}$", RegexOptions.Compiled | RegexOptions.IgnoreCase); static readonly Regex sha1 = new Regex("^[0-9a-f]{40}$", InternalRegexCompiledOption.Default | RegexOptions.IgnoreCase);
internal static bool IsSHA1(string script) internal static bool IsSHA1(string script)
{ {
......
...@@ -23,7 +23,7 @@ public ScriptParameters(RedisKey[] keys, RedisValue[] args) ...@@ -23,7 +23,7 @@ public ScriptParameters(RedisKey[] keys, RedisValue[] args)
} }
} }
static readonly Regex ParameterExtractor = new Regex(@"@(?<paramName> ([a-z]|_) ([a-z]|_|\d)*)", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace); static readonly Regex ParameterExtractor = new Regex(@"@(?<paramName> ([a-z]|_) ([a-z]|_|\d)*)", InternalRegexCompiledOption.Default | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
static string[] ExtractParameters(string script) static string[] ExtractParameters(string script)
{ {
var ps = ParameterExtractor.Matches(script); var ps = ParameterExtractor.Matches(script);
...@@ -313,7 +313,11 @@ static void PrefixIfNeeded(ILGenerator il, LocalBuilder needsPrefixBool, ref Loc ...@@ -313,7 +313,11 @@ static void PrefixIfNeeded(ILGenerator il, LocalBuilder needsPrefixBool, ref Loc
LocalBuilder redisKeyLoc = null; LocalBuilder redisKeyLoc = null;
var loc = il.DeclareLocal(t); var loc = il.DeclareLocal(t);
il.Emit(OpCodes.Ldarg_0); // object il.Emit(OpCodes.Ldarg_0); // object
#if !DNXCORE50
if (t.IsValueType) if (t.IsValueType)
#else
if (t.GetTypeInfo().IsValueType)
#endif
{ {
il.Emit(OpCodes.Unbox_Any, t); // T il.Emit(OpCodes.Unbox_Any, t); // T
} }
...@@ -344,7 +348,11 @@ static void PrefixIfNeeded(ILGenerator il, LocalBuilder needsPrefixBool, ref Loc ...@@ -344,7 +348,11 @@ static void PrefixIfNeeded(ILGenerator il, LocalBuilder needsPrefixBool, ref Loc
{ {
il.Emit(OpCodes.Dup); // RedisKey[] RedisKey[] il.Emit(OpCodes.Dup); // RedisKey[] RedisKey[]
il.Emit(OpCodes.Ldc_I4, i); // RedisKey[] RedisKey[] int il.Emit(OpCodes.Ldc_I4, i); // RedisKey[] RedisKey[] int
#if !DNXCORE50
if (t.IsValueType) if (t.IsValueType)
#else
if (t.GetTypeInfo().IsValueType)
#endif
{ {
il.Emit(OpCodes.Ldloca, loc); // RedisKey[] RedisKey[] int T* il.Emit(OpCodes.Ldloca, loc); // RedisKey[] RedisKey[] int T*
} }
...@@ -372,7 +380,11 @@ static void PrefixIfNeeded(ILGenerator il, LocalBuilder needsPrefixBool, ref Loc ...@@ -372,7 +380,11 @@ static void PrefixIfNeeded(ILGenerator il, LocalBuilder needsPrefixBool, ref Loc
{ {
il.Emit(OpCodes.Dup); // RedisKey[] RedisValue[] RedisValue[] il.Emit(OpCodes.Dup); // RedisKey[] RedisValue[] RedisValue[]
il.Emit(OpCodes.Ldc_I4, i); // RedisKey[] RedisValue[] RedisValue[] int il.Emit(OpCodes.Ldc_I4, i); // RedisKey[] RedisValue[] RedisValue[] int
#if !DNXCORE50
if (t.IsValueType) if (t.IsValueType)
#else
if (t.GetTypeInfo().IsValueType)
#endif
{ {
il.Emit(OpCodes.Ldloca, loc); // RedisKey[] RedisValue[] RedisValue[] int T* il.Emit(OpCodes.Ldloca, loc); // RedisKey[] RedisValue[] RedisValue[] int T*
} }
......
...@@ -26,7 +26,7 @@ internal sealed partial class ServerEndPoint : IDisposable ...@@ -26,7 +26,7 @@ internal sealed partial class ServerEndPoint : IDisposable
{ {
internal volatile ServerEndPoint Master; internal volatile ServerEndPoint Master;
internal volatile ServerEndPoint[] Slaves = NoSlaves; internal volatile ServerEndPoint[] Slaves = NoSlaves;
private static readonly Regex nameSanitizer = new Regex("[^!-~]", RegexOptions.Compiled); private static readonly Regex nameSanitizer = new Regex("[^!-~]", InternalRegexCompiledOption.Default);
private static readonly ServerEndPoint[] NoSlaves = new ServerEndPoint[0]; private static readonly ServerEndPoint[] NoSlaves = new ServerEndPoint[0];
private readonly EndPoint endpoint; private readonly EndPoint endpoint;
...@@ -484,7 +484,7 @@ internal void OnFullyEstablished(PhysicalConnection connection) ...@@ -484,7 +484,7 @@ internal void OnFullyEstablished(PhysicalConnection connection)
internal int LastInfoReplicationCheckSecondsAgo internal int LastInfoReplicationCheckSecondsAgo
{ {
get { return unchecked(Environment.TickCount - Thread.VolatileRead(ref lastInfoReplicationCheckTicks)) / 1000; } get { return unchecked(Environment.TickCount - VolatileWrapper.Read(ref lastInfoReplicationCheckTicks)) / 1000; }
} }
private EndPoint masterEndPoint; private EndPoint masterEndPoint;
......
#if __MonoCS__ #if !FEATURE_SOCKET_MODE_POLL
namespace StackExchange.Redis namespace StackExchange.Redis
{ {
......
using System; #if FEATURE_SOCKET_MODE_POLL
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Net.Sockets; using System.Net.Sockets;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Threading; using System.Threading;
#if !__MonoCS__
namespace StackExchange.Redis namespace StackExchange.Redis
{ {
...@@ -377,9 +377,9 @@ private void ReadImpl() ...@@ -377,9 +377,9 @@ private void ReadImpl()
private void StartReader() private void StartReader()
{ {
var thread = new Thread(read, 32 * 1024); // don't need a huge stack var thread = new Thread(read, 32 * 1024); // don't need a huge stack
thread.Priority = ThreadPriority.AboveNormal; // time critical
thread.Name = name + ":Read"; thread.Name = name + ":Read";
thread.IsBackground = true; thread.IsBackground = true;
thread.Priority = ThreadPriority.AboveNormal; // time critical
thread.Start(this); thread.Start(this);
} }
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
......
...@@ -126,8 +126,12 @@ public SocketManager(string name = null) ...@@ -126,8 +126,12 @@ public SocketManager(string name = null)
// we need a dedicated writer, because when under heavy ambient load // we need a dedicated writer, because when under heavy ambient load
// (a busy asp.net site, for example), workers are not reliable enough // (a busy asp.net site, for example), workers are not reliable enough
#if !DNXCORE50
Thread dedicatedWriter = new Thread(writeAllQueues, 32 * 1024); // don't need a huge stack; Thread dedicatedWriter = new Thread(writeAllQueues, 32 * 1024); // don't need a huge stack;
dedicatedWriter.Priority = ThreadPriority.AboveNormal; // time critical dedicatedWriter.Priority = ThreadPriority.AboveNormal; // time critical
#else
Thread dedicatedWriter = new Thread(writeAllQueues);
#endif
dedicatedWriter.Name = name + ":Write"; dedicatedWriter.Name = name + ":Write";
dedicatedWriter.IsBackground = true; // should not keep process alive dedicatedWriter.IsBackground = true; // should not keep process alive
dedicatedWriter.Start(this); // will self-exit when disposed dedicatedWriter.Start(this); // will self-exit when disposed
...@@ -217,6 +221,7 @@ internal void SetFastLoopbackOption(Socket socket) ...@@ -217,6 +221,7 @@ internal void SetFastLoopbackOption(Socket socket)
// SIO_LOOPBACK_FAST_PATH (http://msdn.microsoft.com/en-us/library/windows/desktop/jj841212%28v=vs.85%29.aspx) // SIO_LOOPBACK_FAST_PATH (http://msdn.microsoft.com/en-us/library/windows/desktop/jj841212%28v=vs.85%29.aspx)
// Speeds up localhost operations significantly. OK to apply to a socket that will not be hooked up to localhost, // Speeds up localhost operations significantly. OK to apply to a socket that will not be hooked up to localhost,
// or will be subject to WFP filtering. // or will be subject to WFP filtering.
#if !DNXCORE50
const int SIO_LOOPBACK_FAST_PATH = -1744830448; const int SIO_LOOPBACK_FAST_PATH = -1744830448;
// windows only // windows only
...@@ -230,6 +235,7 @@ internal void SetFastLoopbackOption(Socket socket) ...@@ -230,6 +235,7 @@ internal void SetFastLoopbackOption(Socket socket)
socket.IOControl(SIO_LOOPBACK_FAST_PATH, optionInValue, null); socket.IOControl(SIO_LOOPBACK_FAST_PATH, optionInValue, null);
} }
} }
#endif
} }
internal void RequestWrite(PhysicalBridge bridge, bool forced) internal void RequestWrite(PhysicalBridge bridge, bool forced)
...@@ -334,7 +340,9 @@ private void Shutdown(Socket socket) ...@@ -334,7 +340,9 @@ private void Shutdown(Socket socket)
{ {
OnShutdown(socket); OnShutdown(socket);
try { socket.Shutdown(SocketShutdown.Both); } catch { } try { socket.Shutdown(SocketShutdown.Both); } catch { }
#if !DNXCORE50
try { socket.Close(); } catch { } try { socket.Close(); } catch { }
#endif
try { socket.Dispose(); } catch { } try { socket.Dispose(); } catch { }
} }
} }
......
...@@ -32,13 +32,19 @@ public SortedSetEntry(RedisValue element, double score) ...@@ -32,13 +32,19 @@ public SortedSetEntry(RedisValue element, double score)
/// <summary> /// <summary>
/// The score against the element /// The score against the element
/// </summary> /// </summary>
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never), Obsolete("Please use Score", false)] #if !DNXCORE50
[Browsable(false)]
#endif
[EditorBrowsable(EditorBrowsableState.Never), Obsolete("Please use Score", false)]
public double Value { get { return score; } } public double Value { get { return score; } }
/// <summary> /// <summary>
/// The unique element stored in the sorted set /// The unique element stored in the sorted set
/// </summary> /// </summary>
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never), Obsolete("Please use Element", false)] #if !DNXCORE50
[Browsable(false)]
#endif
[EditorBrowsable(EditorBrowsableState.Never), Obsolete("Please use Element", false)]
public RedisValue Key { get { return element; } } public RedisValue Key { get { return element; } }
/// <summary> /// <summary>
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
<DebugType>full</DebugType> <DebugType>full</DebugType>
<Optimize>false</Optimize> <Optimize>false</Optimize>
<OutputPath>bin.snk\Debug\</OutputPath> <OutputPath>bin.snk\Debug\</OutputPath>
<DefineConstants>TRACE;DEBUG;NET40 STRONG_NAME</DefineConstants> <DefineConstants>TRACE;DEBUG;NET40 STRONG_NAME 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>
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
<DebugType>pdbonly</DebugType> <DebugType>pdbonly</DebugType>
<Optimize>true</Optimize> <Optimize>true</Optimize>
<OutputPath>bin.snk\Release\</OutputPath> <OutputPath>bin.snk\Release\</OutputPath>
<DefineConstants>TRACE;NET40 STRONG_NAME</DefineConstants> <DefineConstants>TRACE;NET40 STRONG_NAME FEATURE_SERIALIZATION FEATURE_SOCKET_MODE_POLL</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<UseVSHostingProcess>false</UseVSHostingProcess> <UseVSHostingProcess>false</UseVSHostingProcess>
...@@ -43,7 +43,7 @@ ...@@ -43,7 +43,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;NET40 STRONG_NAME</DefineConstants> <DefineConstants>TRACE;NET40 STRONG_NAME FEATURE_SERIALIZATION</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DocumentationFile>bin.snk\Release\StackExchange.Redis.StrongName.xml</DocumentationFile> <DocumentationFile>bin.snk\Release\StackExchange.Redis.StrongName.xml</DocumentationFile>
<Optimize>true</Optimize> <Optimize>true</Optimize>
...@@ -85,6 +85,9 @@ ...@@ -85,6 +85,9 @@
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ClientType.cs"> <Compile Include="..\StackExchange.Redis\StackExchange\Redis\ClientType.cs">
<Link>ClientType.cs</Link> <Link>ClientType.cs</Link>
</Compile> </Compile>
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\Compat\VolatileWrapper.cs">
<Link>VolatileWrapper.cs</Link>
</Compile>
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ConcurrentProfileStorageCollection.cs" /> <Compile Include="..\StackExchange.Redis\StackExchange\Redis\ConcurrentProfileStorageCollection.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ConnectionMultiplexer.Profiling.cs"> <Compile Include="..\StackExchange.Redis\StackExchange\Redis\ConnectionMultiplexer.Profiling.cs">
<DependentUpon>ConnectionMultiplexer.cs</DependentUpon> <DependentUpon>ConnectionMultiplexer.cs</DependentUpon>
...@@ -120,6 +123,7 @@ ...@@ -120,6 +123,7 @@
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\IDatabaseAsync.cs" /> <Compile Include="..\StackExchange.Redis\StackExchange\Redis\IDatabaseAsync.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\IMultiMessage.cs" /> <Compile Include="..\StackExchange.Redis\StackExchange\Redis\IMultiMessage.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\InternalErrorEventArgs.cs" /> <Compile Include="..\StackExchange.Redis\StackExchange\Redis\InternalErrorEventArgs.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\InternalRegexCompiledOption.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\IProfiler.cs" /> <Compile Include="..\StackExchange.Redis\StackExchange\Redis\IProfiler.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\IRedis.cs" /> <Compile Include="..\StackExchange.Redis\StackExchange\Redis\IRedis.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\IRedisAsync.cs" /> <Compile Include="..\StackExchange.Redis\StackExchange\Redis\IRedisAsync.cs" />
......
...@@ -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;NET40</DefineConstants> <DefineConstants>TRACE;DEBUG;NET40 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>
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
<DebugType>pdbonly</DebugType> <DebugType>pdbonly</DebugType>
<Optimize>true</Optimize> <Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath> <OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE;NET40</DefineConstants> <DefineConstants>TRACE;NET40 FEATURE_SERIALIZATION FEATURE_SOCKET_MODE_POLL</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<UseVSHostingProcess>false</UseVSHostingProcess> <UseVSHostingProcess>false</UseVSHostingProcess>
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,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;NET40</DefineConstants> <DefineConstants>TRACE;NET40 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>
...@@ -82,6 +82,9 @@ ...@@ -82,6 +82,9 @@
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ClientType.cs"> <Compile Include="..\StackExchange.Redis\StackExchange\Redis\ClientType.cs">
<Link>ClientType.cs</Link> <Link>ClientType.cs</Link>
</Compile> </Compile>
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\Compat\VolatileWrapper.cs">
<Link>VolatileWrapper.cs</Link>
</Compile>
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ConcurrentProfileStorageCollection.cs" /> <Compile Include="..\StackExchange.Redis\StackExchange\Redis\ConcurrentProfileStorageCollection.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ConnectionMultiplexer.Profiling.cs"> <Compile Include="..\StackExchange.Redis\StackExchange\Redis\ConnectionMultiplexer.Profiling.cs">
<DependentUpon>ConnectionMultiplexer.cs</DependentUpon> <DependentUpon>ConnectionMultiplexer.cs</DependentUpon>
...@@ -117,6 +120,7 @@ ...@@ -117,6 +120,7 @@
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\IDatabaseAsync.cs" /> <Compile Include="..\StackExchange.Redis\StackExchange\Redis\IDatabaseAsync.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\IMultiMessage.cs" /> <Compile Include="..\StackExchange.Redis\StackExchange\Redis\IMultiMessage.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\InternalErrorEventArgs.cs" /> <Compile Include="..\StackExchange.Redis\StackExchange\Redis\InternalErrorEventArgs.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\InternalRegexCompiledOption.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\IProfiler.cs" /> <Compile Include="..\StackExchange.Redis\StackExchange\Redis\IProfiler.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\IRedis.cs" /> <Compile Include="..\StackExchange.Redis\StackExchange\Redis\IRedis.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\IRedisAsync.cs" /> <Compile Include="..\StackExchange.Redis\StackExchange\Redis\IRedisAsync.cs" />
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
<DebugType>full</DebugType> <DebugType>full</DebugType>
<Optimize>false</Optimize> <Optimize>false</Optimize>
<OutputPath>bin.snk\Debug\</OutputPath> <OutputPath>bin.snk\Debug\</OutputPath>
<DefineConstants>TRACE;DEBUG;NET46 PLAT_SAFE_CONTINUATIONS STRONG_NAME</DefineConstants> <DefineConstants>TRACE;DEBUG;NET46 PLAT_SAFE_CONTINUATIONS STRONG_NAME 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>
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
<DebugType>pdbonly</DebugType> <DebugType>pdbonly</DebugType>
<Optimize>true</Optimize> <Optimize>true</Optimize>
<OutputPath>bin.snk\Release\</OutputPath> <OutputPath>bin.snk\Release\</OutputPath>
<DefineConstants>TRACE;NET46 PLAT_SAFE_CONTINUATIONS STRONG_NAME</DefineConstants> <DefineConstants>TRACE;NET46 PLAT_SAFE_CONTINUATIONS STRONG_NAME FEATURE_SERIALIZATION FEATURE_SOCKET_MODE_POLL</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<UseVSHostingProcess>false</UseVSHostingProcess> <UseVSHostingProcess>false</UseVSHostingProcess>
...@@ -46,7 +46,7 @@ ...@@ -46,7 +46,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;NET46 PLAT_SAFE_CONTINUATIONS STRONG_NAME</DefineConstants> <DefineConstants>TRACE;NET46 PLAT_SAFE_CONTINUATIONS STRONG_NAME FEATURE_SERIALIZATION</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DocumentationFile>bin.snk\Release\StackExchange.Redis.StrongName.xml</DocumentationFile> <DocumentationFile>bin.snk\Release\StackExchange.Redis.StrongName.xml</DocumentationFile>
<Optimize>true</Optimize> <Optimize>true</Optimize>
...@@ -71,6 +71,9 @@ ...@@ -71,6 +71,9 @@
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ClientType.cs"> <Compile Include="..\StackExchange.Redis\StackExchange\Redis\ClientType.cs">
<Link>ClientType.cs</Link> <Link>ClientType.cs</Link>
</Compile> </Compile>
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\Compat\VolatileWrapper.cs">
<Link>VolatileWrapper.cs</Link>
</Compile>
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ConcurrentProfileStorageCollection.cs" /> <Compile Include="..\StackExchange.Redis\StackExchange\Redis\ConcurrentProfileStorageCollection.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ConnectionMultiplexer.Profiling.cs"> <Compile Include="..\StackExchange.Redis\StackExchange\Redis\ConnectionMultiplexer.Profiling.cs">
<DependentUpon>ConnectionMultiplexer.cs</DependentUpon> <DependentUpon>ConnectionMultiplexer.cs</DependentUpon>
...@@ -106,6 +109,7 @@ ...@@ -106,6 +109,7 @@
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\IDatabaseAsync.cs" /> <Compile Include="..\StackExchange.Redis\StackExchange\Redis\IDatabaseAsync.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\IMultiMessage.cs" /> <Compile Include="..\StackExchange.Redis\StackExchange\Redis\IMultiMessage.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\InternalErrorEventArgs.cs" /> <Compile Include="..\StackExchange.Redis\StackExchange\Redis\InternalErrorEventArgs.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\InternalRegexCompiledOption.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\IProfiler.cs" /> <Compile Include="..\StackExchange.Redis\StackExchange\Redis\IProfiler.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\IRedis.cs" /> <Compile Include="..\StackExchange.Redis\StackExchange\Redis\IRedis.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\IRedisAsync.cs" /> <Compile Include="..\StackExchange.Redis\StackExchange\Redis\IRedisAsync.cs" />
......
...@@ -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;NET46 PLAT_SAFE_CONTINUATIONS</DefineConstants> <DefineConstants>TRACE;DEBUG;NET46 PLAT_SAFE_CONTINUATIONS 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>
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
<DebugType>pdbonly</DebugType> <DebugType>pdbonly</DebugType>
<Optimize>true</Optimize> <Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath> <OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE;NET46 PLAT_SAFE_CONTINUATIONS</DefineConstants> <DefineConstants>TRACE;NET46 PLAT_SAFE_CONTINUATIONS FEATURE_SERIALIZATION FEATURE_SOCKET_MODE_POLL</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<UseVSHostingProcess>false</UseVSHostingProcess> <UseVSHostingProcess>false</UseVSHostingProcess>
...@@ -40,7 +40,7 @@ ...@@ -40,7 +40,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;NET46 PLAT_SAFE_CONTINUATIONS</DefineConstants> <DefineConstants>TRACE;NET46 PLAT_SAFE_CONTINUATIONS 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>
...@@ -65,6 +65,9 @@ ...@@ -65,6 +65,9 @@
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ClientType.cs"> <Compile Include="..\StackExchange.Redis\StackExchange\Redis\ClientType.cs">
<Link>ClientType.cs</Link> <Link>ClientType.cs</Link>
</Compile> </Compile>
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\Compat\VolatileWrapper.cs">
<Link>VolatileWrapper.cs</Link>
</Compile>
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ConcurrentProfileStorageCollection.cs" /> <Compile Include="..\StackExchange.Redis\StackExchange\Redis\ConcurrentProfileStorageCollection.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ConnectionMultiplexer.Profiling.cs"> <Compile Include="..\StackExchange.Redis\StackExchange\Redis\ConnectionMultiplexer.Profiling.cs">
<DependentUpon>ConnectionMultiplexer.cs</DependentUpon> <DependentUpon>ConnectionMultiplexer.cs</DependentUpon>
...@@ -100,6 +103,7 @@ ...@@ -100,6 +103,7 @@
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\IDatabaseAsync.cs" /> <Compile Include="..\StackExchange.Redis\StackExchange\Redis\IDatabaseAsync.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\IMultiMessage.cs" /> <Compile Include="..\StackExchange.Redis\StackExchange\Redis\IMultiMessage.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\InternalErrorEventArgs.cs" /> <Compile Include="..\StackExchange.Redis\StackExchange\Redis\InternalErrorEventArgs.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\InternalRegexCompiledOption.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\IProfiler.cs" /> <Compile Include="..\StackExchange.Redis\StackExchange\Redis\IProfiler.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\IRedis.cs" /> <Compile Include="..\StackExchange.Redis\StackExchange\Redis\IRedis.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\IRedisAsync.cs" /> <Compile Include="..\StackExchange.Redis\StackExchange\Redis\IRedisAsync.cs" />
......
<?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>86526b5c-1163-4481-a5e2-a303a0bb1535</ProjectGuid>
<RootNamespace>StackExchange.Redis</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.1.0-*",
"description": "StackExchange.Redis",
"authors": [ "jeremymeng" ],
"tags": [ "" ],
"projectUrl": "",
"licenseUrl": "",
"compile": [
"../../StackExchange.Redis/**/*.cs"
],
"dependencies": {
},
"configurations": {
"Debug": {
"compilationOptions": {
"define": [ "DEBUG", "TRACE" ],
"allowUnsafe": true
}
},
"Release": {
"compilationOptions": {
"define": [ "TRACE" ],
"allowUnsafe": true
}
}
},
"frameworks": {
"dnxcore50": {
"dependencies": {
"System.Diagnostics.Debug": "4.0.0",
"System.Diagnostics.TraceSource": "4.0.0-beta-23409",
"System.Diagnostics.Tools": "4.0.0",
"System.IO.Compression": "4.0.0",
"System.Globalization": "4.0.10",
"System.Linq": "4.0.0",
"System.Net.Primitives": "4.0.10",
"System.Net.Sockets": "4.1.0-beta-23409",
"System.Net.Security": "4.0.0-beta-23409",
"System.Net.NameResolution": "4.0.0-beta-23409",
"System.Reflection": "4.0.0",
"System.Reflection.Emit": "4.0.0",
"System.Reflection.TypeExtensions": "4.0.0",
"System.Reflection.Primitives": "4.0.0",
"System.Reflection.Emit.Lightweight": "4.0.0",
"System.Security.Cryptography.Algorithms": "4.0.0-beta-23409",
"System.Security.Cryptography.X509Certificates": "4.0.0-beta-23409",
"System.Text.RegularExpressions": "4.0.10",
"System.Threading": "4.0.0",
"System.Threading.Thread": "4.0.0-*",
"System.Threading.ThreadPool": "4.0.10-beta-23409",
"System.Threading.Timer": "4.0.1-beta-23409",
"System.Threading.Tasks": "4.0.0"
}
}
}
}
\ No newline at end of file
{
"sdk": {
"version": "1.0.0-beta8",
"runtime": "coreclr",
"architecture": "x86"
},
"projects": [ "StackExchange.Redis_dnxcore50" ]
}
Copyright © 2002-2014 Charlie Poole
Copyright © 2002-2004 James W. Newkirk, Michael C. Two, Alexei A. Vorontsov
Copyright © 2000-2002 Philip A. Craig
This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment (see the following) in the product documentation is required.
Portions Copyright © 2002-2014 Charlie Poole or Copyright © 2002-2004 James W. Newkirk, Michael C. Two, Alexei A. Vorontsov or Copyright © 2000-2002 Philip A. Craig
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
This diff is collapsed.
Copyright (c) 2015 Charlie Poole
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
NUnit 3.0 is based on earlier versions of NUnit, with Portions
Copyright (c) 2002-2014 Charlie Poole or
Copyright (c) 2002-2004 James W. Newkirk, Michael C. Two, Alexei A. Vorontsov or
Copyright (c) 2000-2002 Philip A. Craig
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