Commit fe8544b2 authored by Jeremy Meng's avatar Jeremy Meng

Attempt to fix the whitespace/encoding issue with Emacs.

parent 790bb080
.hg
bin
bin.snk
obj
*.suo
*.user
*.nupkg
packages/NuGet.CommandLine.*
*.sln.docstates
_ReSharper.*
Mono/
*.sln.ide
*.rdb
*.aof
*.orig
redis-cli.exe
Redis Configs/*.dat
RedisQFork*.dat
StackExchange.Redis.*.zip
.vs/
*.lock.json
\ No newline at end of file
.hg
bin
bin.snk
obj
*.suo
*.user
*.nupkg
packages/NuGet.CommandLine.*
*.sln.docstates
_ReSharper.*
Mono/
*.sln.ide
*.rdb
*.aof
*.orig
redis-cli.exe
Redis Configs/*.dat
RedisQFork*.dat
StackExchange.Redis.*.zip
.vs/
*.lock.json
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
#if FEATURE_BOOKSLEEVE
using BookSleeve;
#endif
using NUnit.Framework;
using StackExchange.Redis.KeyspaceIsolation;
namespace StackExchange.Redis.Tests
{
[TestFixture]
public class BasicOpsTests : TestBase
{
[Test]
[TestCase(true)]
[TestCase(false)]
public void PingOnce(bool preserveOrder)
{
using (var muxer = Create())
{
muxer.PreserveAsyncOrder = preserveOrder;
var conn = muxer.GetDatabase();
var task = conn.PingAsync();
var duration = muxer.Wait(task);
Console.WriteLine("Ping took: " + duration);
Assert.IsTrue(duration.TotalMilliseconds > 0);
}
}
[Test]
[TestCase(true)]
[TestCase(false)]
public void RapidDispose(bool preserverOrder)
{
RedisKey key = Me();
using (var primary = Create())
{
var conn = primary.GetDatabase();
conn.KeyDelete(key);
for (int i = 0; i < 10; i++)
{
using (var secondary = Create(fail: true))
{
secondary.GetDatabase().StringIncrement(key, flags: CommandFlags.FireAndForget);
}
}
Assert.AreEqual(10, (int)conn.StringGet(key));
}
}
[Test]
[TestCase(true)]
[TestCase(false)]
public void PingMany(bool preserveOrder)
{
using (var muxer = Create())
{
muxer.PreserveAsyncOrder = preserveOrder;
var conn = muxer.GetDatabase();
var tasks = new Task<TimeSpan>[10000];
for (int i = 0; i < tasks.Length; i++)
{
tasks[i] = conn.PingAsync();
}
muxer.WaitAll(tasks);
Assert.IsTrue(tasks[0].Result.TotalMilliseconds > 0);
Assert.IsTrue(tasks[tasks.Length - 1].Result.TotalMilliseconds > 0);
}
}
[Test]
public void GetWithNullKey()
{
using (var muxer = Create())
{
var db = muxer.GetDatabase();
string key = null;
Assert.Throws<ArgumentException>(
() => db.StringGet(key),
"A null key is not valid in this context");
}
}
[Test]
public void SetWithNullKey()
{
using (var muxer = Create())
{
var db = muxer.GetDatabase();
string key = null, value = "abc";
Assert.Throws<ArgumentException>(
() => db.StringSet(key, value),
"A null key is not valid in this context");
}
}
[Test]
public void SetWithNullValue()
{
using (var muxer = Create())
{
var db = muxer.GetDatabase();
string key = Me(), value = null;
db.KeyDelete(key, CommandFlags.FireAndForget);
db.StringSet(key, "abc", flags: CommandFlags.FireAndForget);
Assert.IsTrue(db.KeyExists(key));
db.StringSet(key, value);
var actual = (string)db.StringGet(key);
Assert.IsNull(actual);
Assert.IsFalse(db.KeyExists(key));
}
}
[Test]
public void SetWithDefaultValue()
{
using (var muxer = Create())
{
var db = muxer.GetDatabase();
string key = Me();
var value = default(RedisValue); // this is kinda 0... ish
db.KeyDelete(key, CommandFlags.FireAndForget);
db.StringSet(key, "abc", flags: CommandFlags.FireAndForget);
Assert.IsTrue(db.KeyExists(key));
db.StringSet(key, value);
var actual = (string)db.StringGet(key);
Assert.IsNull(actual);
Assert.IsFalse(db.KeyExists(key));
}
}
[Test]
public void SetWithZeroValue()
{
using (var muxer = Create())
{
var db = muxer.GetDatabase();
string key = Me();
long value = 0;
db.KeyDelete(key, CommandFlags.FireAndForget);
db.StringSet(key, "abc", flags: CommandFlags.FireAndForget);
Assert.IsTrue(db.KeyExists(key));
db.StringSet(key, value);
var actual = (string)db.StringGet(key);
Assert.AreEqual("0", actual);
Assert.IsTrue(db.KeyExists(key));
}
}
[Test]
[TestCase(true)]
[TestCase(false)]
public void GetSetAsync(bool preserveOrder)
{
using (var muxer = Create())
{
muxer.PreserveAsyncOrder = preserveOrder;
var conn = muxer.GetDatabase();
RedisKey key = Me();
var d0 = conn.KeyDeleteAsync(key);
var d1 = conn.KeyDeleteAsync(key);
var g1 = conn.StringGetAsync(key);
var s1 = conn.StringSetAsync(key, "123");
var g2 = conn.StringGetAsync(key);
var d2 = conn.KeyDeleteAsync(key);
muxer.Wait(d0);
Assert.IsFalse(muxer.Wait(d1));
Assert.IsNull((string)muxer.Wait(g1));
Assert.IsTrue(muxer.Wait(g1).IsNull);
muxer.Wait(s1);
Assert.AreEqual("123", (string)muxer.Wait(g2));
Assert.AreEqual(123, (int)muxer.Wait(g2));
Assert.IsFalse(muxer.Wait(g2).IsNull);
Assert.IsTrue(muxer.Wait(d2));
}
}
[Test]
[TestCase(true)]
[TestCase(false)]
public void GetSetSync(bool preserveOrder)
{
using (var muxer = Create())
{
muxer.PreserveAsyncOrder = preserveOrder;
var conn = muxer.GetDatabase();
RedisKey key = Me();
conn.KeyDelete(key);
var d1 = conn.KeyDelete(key);
var g1 = conn.StringGet(key);
conn.StringSet(key, "123");
var g2 = conn.StringGet(key);
var d2 = conn.KeyDelete(key);
Assert.IsFalse(d1);
Assert.IsNull((string)g1);
Assert.IsTrue(g1.IsNull);
Assert.AreEqual("123", (string)g2);
Assert.AreEqual(123, (int)g2);
Assert.IsFalse(g2.IsNull);
Assert.IsTrue(d2);
}
}
[Test]
[TestCase(true, true)]
[TestCase(true, false)]
[TestCase(false, true)]
[TestCase(false, false)]
public void MassiveBulkOpsAsync(bool preserveOrder, bool withContinuation)
{
#if DEBUG
var oldAsyncCompletionCount = ConnectionMultiplexer.GetAsyncCompletionWorkerCount();
#endif
using (var muxer = Create())
{
muxer.PreserveAsyncOrder = preserveOrder;
RedisKey key = "MBOA";
var conn = muxer.GetDatabase();
muxer.Wait(conn.PingAsync());
#if DNXCORE50
int number = 0;
#endif
Action<Task> nonTrivial = delegate
{
#if !DNXCORE50
Thread.SpinWait(5);
#else
for (int i = 0; i < 50; i++)
{
number++;
}
#endif
};
var watch = Stopwatch.StartNew();
for (int i = 0; i <= AsyncOpsQty; i++)
{
var t = conn.StringSetAsync(key, i);
if (withContinuation) t.ContinueWith(nonTrivial);
}
int val = (int)muxer.Wait(conn.StringGetAsync(key));
Assert.AreEqual(AsyncOpsQty, val);
watch.Stop();
Console.WriteLine("{2}: Time for {0} ops: {1}ms ({3}, {4}); ops/s: {5}", AsyncOpsQty, watch.ElapsedMilliseconds, Me(),
withContinuation ? "with continuation" : "no continuation", preserveOrder ? "preserve order" : "any order",
AsyncOpsQty / watch.Elapsed.TotalSeconds);
#if DEBUG
Console.WriteLine("Async completion workers: " + (ConnectionMultiplexer.GetAsyncCompletionWorkerCount() - oldAsyncCompletionCount));
#endif
}
}
[Test]
[TestCase(false, false)]
[TestCase(true, true)]
[TestCase(true, false)]
public void GetWithExpiry(bool exists, bool hasExpiry)
{
using(var conn = Create())
{
var db = conn.GetDatabase();
RedisKey key = Me();
db.KeyDelete(key);
if (exists)
{
if (hasExpiry)
db.StringSet(key, "val", TimeSpan.FromMinutes(5));
else
db.StringSet(key, "val");
}
var async = db.StringGetWithExpiryAsync(key);
var syncResult = db.StringGetWithExpiry(key);
var asyncResult = db.Wait(async);
if(exists)
{
Assert.AreEqual("val", (string)asyncResult.Value);
Assert.AreEqual(hasExpiry, asyncResult.Expiry.HasValue);
if (hasExpiry) Assert.IsTrue(asyncResult.Expiry.Value.TotalMinutes >= 4.9 && asyncResult.Expiry.Value.TotalMinutes <= 5);
Assert.AreEqual("val", (string)syncResult.Value);
Assert.AreEqual(hasExpiry, syncResult.Expiry.HasValue);
if (hasExpiry) Assert.IsTrue(syncResult.Expiry.Value.TotalMinutes >= 4.9 && syncResult.Expiry.Value.TotalMinutes <= 5);
}
else
{
Assert.IsTrue(asyncResult.Value.IsNull);
Assert.IsFalse(asyncResult.Expiry.HasValue);
Assert.IsTrue(syncResult.Value.IsNull);
Assert.IsFalse(syncResult.Expiry.HasValue);
}
}
}
[Test]
public void GetWithExpiryWrongTypeAsync()
{
using (var conn = Create())
{
var db = conn.GetDatabase();
RedisKey key = Me();
db.KeyDelete(key);
db.SetAdd(key, "abc");
Assert.Throws<RedisServerException>(() =>
{
try
{
var async = db.Wait(db.StringGetWithExpiryAsync(key));
}
catch (AggregateException ex)
{
throw ex.InnerExceptions[0];
}
Assert.Fail();
},
"A null key is not valid in this context");
}
}
[Test]
public void GetWithExpiryWrongTypeSync()
{
Assert.Throws<RedisServerException>(() =>
{
using (var conn = Create())
{
var db = conn.GetDatabase();
RedisKey key = Me();
db.KeyDelete(key);
db.SetAdd(key, "abc");
db.StringGetWithExpiry(key);
Assert.Fail();
}
},
"WRONGTYPE Operation against a key holding the wrong kind of value");
}
#if FEATURE_BOOKSLEEVE
[Test]
[TestCase(true, true, ResultCompletionMode.ConcurrentIfContinuation)]
[TestCase(true, false, ResultCompletionMode.ConcurrentIfContinuation)]
[TestCase(false, true, ResultCompletionMode.ConcurrentIfContinuation)]
[TestCase(false, false, ResultCompletionMode.ConcurrentIfContinuation)]
[TestCase(true, true, ResultCompletionMode.Concurrent)]
[TestCase(true, false, ResultCompletionMode.Concurrent)]
[TestCase(false, true, ResultCompletionMode.Concurrent)]
[TestCase(false, false, ResultCompletionMode.Concurrent)]
[TestCase(true, true, ResultCompletionMode.PreserveOrder)]
[TestCase(true, false, ResultCompletionMode.PreserveOrder)]
[TestCase(false, true, ResultCompletionMode.PreserveOrder)]
[TestCase(false, false, ResultCompletionMode.PreserveOrder)]
public void MassiveBulkOpsAsyncOldStyle(bool withContinuation, bool suspendFlush, ResultCompletionMode completionMode)
{
using (var conn = GetOldStyleConnection())
{
const int db = 0;
string key = "MBOQ";
conn.CompletionMode = completionMode;
conn.Wait(conn.Server.Ping());
Action<Task> nonTrivial = delegate
{
Thread.SpinWait(5);
};
var watch = Stopwatch.StartNew();
if (suspendFlush) conn.SuspendFlush();
try
{
for (int i = 0; i <= AsyncOpsQty; i++)
{
var t = conn.Strings.Set(db, key, i);
if (withContinuation) t.ContinueWith(nonTrivial);
}
} finally
{
if (suspendFlush) conn.ResumeFlush();
}
int val = (int)conn.Wait(conn.Strings.GetInt64(db, key));
Assert.AreEqual(AsyncOpsQty, val);
watch.Stop();
Console.WriteLine("{2}: Time for {0} ops: {1}ms ({3}, {4}, {5}); ops/s: {6}", AsyncOpsQty, watch.ElapsedMilliseconds, Me(),
withContinuation ? "with continuation" : "no continuation",
suspendFlush ? "suspend flush" : "flush at whim",
completionMode, AsyncOpsQty / watch.Elapsed.TotalSeconds);
}
}
#endif
[Test]
[TestCase(true, 1)]
[TestCase(false, 1)]
[TestCase(true, 5)]
[TestCase(false, 5)]
[TestCase(true, 10)]
[TestCase(false, 10)]
[TestCase(true, 50)]
[TestCase(false, 50)]
public void MassiveBulkOpsSync(bool preserveOrder, int threads)
{
int workPerThread = SyncOpsQty / threads;
using (var muxer = Create())
{
muxer.PreserveAsyncOrder = preserveOrder;
RedisKey key = "MBOS";
var conn = muxer.GetDatabase();
conn.KeyDelete(key);
#if DEBUG
long oldAlloc = ConnectionMultiplexer.GetResultBoxAllocationCount();
long oldWorkerCount = ConnectionMultiplexer.GetAsyncCompletionWorkerCount();
#endif
var timeTaken = RunConcurrent(delegate
{
for (int i = 0; i < workPerThread; i++)
{
conn.StringIncrement(key);
}
}, threads);
int val = (int)conn.StringGet(key);
Assert.AreEqual(workPerThread * threads, val);
Console.WriteLine("{2}: Time for {0} ops on {4} threads: {1}ms ({3}); ops/s: {5}",
threads * workPerThread, timeTaken.TotalMilliseconds, Me()
, preserveOrder ? "preserve order" : "any order", threads, (workPerThread * threads) / timeTaken.TotalSeconds);
#if DEBUG
long newAlloc = ConnectionMultiplexer.GetResultBoxAllocationCount();
long newWorkerCount = ConnectionMultiplexer.GetAsyncCompletionWorkerCount();
Console.WriteLine("ResultBox allocations: {0}; workers {1}", newAlloc - oldAlloc, newWorkerCount - oldWorkerCount);
Assert.IsTrue(newAlloc - oldAlloc <= 2 * threads, "number of box allocations");
#endif
}
}
#if FEATURE_BOOKSLEEVE
[Test]
[TestCase(ResultCompletionMode.Concurrent, 1)]
[TestCase(ResultCompletionMode.ConcurrentIfContinuation, 1)]
[TestCase(ResultCompletionMode.PreserveOrder, 1)]
[TestCase(ResultCompletionMode.Concurrent, 5)]
[TestCase(ResultCompletionMode.ConcurrentIfContinuation, 5)]
[TestCase(ResultCompletionMode.PreserveOrder, 5)]
[TestCase(ResultCompletionMode.Concurrent, 10)]
[TestCase(ResultCompletionMode.ConcurrentIfContinuation, 10)]
[TestCase(ResultCompletionMode.PreserveOrder, 10)]
[TestCase(ResultCompletionMode.Concurrent, 50)]
[TestCase(ResultCompletionMode.ConcurrentIfContinuation, 50)]
[TestCase(ResultCompletionMode.PreserveOrder, 50)]
public void MassiveBulkOpsSyncOldStyle(ResultCompletionMode completionMode, int threads)
{
int workPerThread = SyncOpsQty / threads;
using (var conn = GetOldStyleConnection())
{
const int db = 0;
string key = "MBOQ";
conn.CompletionMode = completionMode;
conn.Wait(conn.Keys.Remove(db, key));
var timeTaken = RunConcurrent(delegate
{
for (int i = 0; i < workPerThread; i++)
{
conn.Wait(conn.Strings.Increment(db, key));
}
}, threads);
int val = (int)conn.Wait(conn.Strings.GetInt64(db, key));
Assert.AreEqual(workPerThread * threads, val);
Console.WriteLine("{2}: Time for {0} ops on {4} threads: {1}ms ({3}); ops/s: {5}", workPerThread * threads, timeTaken.TotalMilliseconds, Me(),
completionMode, threads, (workPerThread * threads) / timeTaken.TotalSeconds);
}
}
#endif
[Test]
[TestCase(true, 1)]
[TestCase(false, 1)]
[TestCase(true, 5)]
[TestCase(false, 5)]
public void MassiveBulkOpsFireAndForget(bool preserveOrder, int threads)
{
using (var muxer = Create())
{
muxer.PreserveAsyncOrder = preserveOrder;
#if DEBUG
long oldAlloc = ConnectionMultiplexer.GetResultBoxAllocationCount();
#endif
RedisKey key = "MBOF";
var conn = muxer.GetDatabase();
conn.Ping();
conn.KeyDelete(key, CommandFlags.FireAndForget);
int perThread = AsyncOpsQty / threads;
var elapsed = RunConcurrent(delegate
{
for (int i = 0; i < perThread; i++)
{
conn.StringIncrement(key, flags: CommandFlags.FireAndForget);
}
conn.Ping();
}, threads);
var val = (long)conn.StringGet(key);
Assert.AreEqual(perThread * threads, val);
Console.WriteLine("{2}: Time for {0} ops over {5} threads: {1:###,###}ms ({3}); ops/s: {4:###,###,##0}",
val, elapsed.TotalMilliseconds, Me(),
preserveOrder ? "preserve order" : "any order",
val / elapsed.TotalSeconds, threads);
#if DEBUG
long newAlloc = ConnectionMultiplexer.GetResultBoxAllocationCount();
Console.WriteLine("ResultBox allocations: {0}",
newAlloc - oldAlloc);
Assert.IsTrue(newAlloc - oldAlloc <= 4);
#endif
}
}
#if DEBUG
[Test]
[TestCase(true)]
[TestCase(false)]
public void TestQuit(bool preserveOrder)
{
SetExpectedAmbientFailureCount(1);
using (var muxer = Create(allowAdmin: true))
{
muxer.PreserveAsyncOrder = preserveOrder;
var db = muxer.GetDatabase();
string key = Guid.NewGuid().ToString();
db.KeyDelete(key, CommandFlags.FireAndForget);
db.StringSet(key, key, flags: CommandFlags.FireAndForget);
GetServer(muxer).Quit(CommandFlags.FireAndForget);
var watch = Stopwatch.StartNew();
try
{
db.Ping();
Assert.Fail();
}
catch (RedisConnectionException) { }
watch.Stop();
Console.WriteLine("Time to notice quit: {0}ms ({1})", watch.ElapsedMilliseconds,
preserveOrder ? "preserve order" : "any order");
Thread.Sleep(20);
Debug.WriteLine("Pinging...");
Assert.AreEqual(key, (string)db.StringGet(key));
}
}
[Test]
[TestCase(true)]
[TestCase(false)]
public void TestSevered(bool preserveOrder)
{
SetExpectedAmbientFailureCount(2);
using (var muxer = Create(allowAdmin: true))
{
muxer.PreserveAsyncOrder = preserveOrder;
var db = muxer.GetDatabase();
string key = Guid.NewGuid().ToString();
db.KeyDelete(key, CommandFlags.FireAndForget);
db.StringSet(key, key, flags: CommandFlags.FireAndForget);
GetServer(muxer).SimulateConnectionFailure();
var watch = Stopwatch.StartNew();
db.Ping();
watch.Stop();
Console.WriteLine("Time to re-establish: {0}ms ({1})", watch.ElapsedMilliseconds,
preserveOrder ? "preserve order" : "any order");
Thread.Sleep(20);
Debug.WriteLine("Pinging...");
Assert.AreEqual(key, (string)db.StringGet(key));
}
}
#endif
[Test]
[TestCase(true)]
[TestCase(false)]
public void IncrAsync(bool preserveOrder)
{
using (var muxer = Create())
{
muxer.PreserveAsyncOrder = preserveOrder;
var conn = muxer.GetDatabase();
RedisKey key = Me();
conn.KeyDelete(key, CommandFlags.FireAndForget);
var nix = conn.KeyExistsAsync(key);
var a = conn.StringGetAsync(key);
var b = conn.StringIncrementAsync(key);
var c = conn.StringGetAsync(key);
var d = conn.StringIncrementAsync(key, 10);
var e = conn.StringGetAsync(key);
var f = conn.StringDecrementAsync(key, 11);
var g = conn.StringGetAsync(key);
var h = conn.KeyExistsAsync(key);
Assert.IsFalse(muxer.Wait(nix));
Assert.IsTrue(muxer.Wait(a).IsNull);
Assert.AreEqual(0, (long)muxer.Wait(a));
Assert.AreEqual(1, muxer.Wait(b));
Assert.AreEqual(1, (long)muxer.Wait(c));
Assert.AreEqual(11, muxer.Wait(d));
Assert.AreEqual(11, (long)muxer.Wait(e));
Assert.AreEqual(0, muxer.Wait(f));
Assert.AreEqual(0, (long)muxer.Wait(g));
Assert.IsTrue(muxer.Wait(h));
}
}
[Test]
[TestCase(true)]
[TestCase(false)]
public void IncrSync(bool preserveOrder)
{
using (var muxer = Create())
{
muxer.PreserveAsyncOrder = preserveOrder;
var conn = muxer.GetDatabase();
RedisKey key = Me();
conn.KeyDelete(key, CommandFlags.FireAndForget);
var nix = conn.KeyExists(key);
var a = conn.StringGet(key);
var b = conn.StringIncrement(key);
var c = conn.StringGet(key);
var d = conn.StringIncrement(key, 10);
var e = conn.StringGet(key);
var f = conn.StringDecrement(key, 11);
var g = conn.StringGet(key);
var h = conn.KeyExists(key);
Assert.IsFalse(nix);
Assert.IsTrue(a.IsNull);
Assert.AreEqual(0, (long)a);
Assert.AreEqual(1, b);
Assert.AreEqual(1, (long)c);
Assert.AreEqual(11, d);
Assert.AreEqual(11, (long)e);
Assert.AreEqual(0, f);
Assert.AreEqual(0, (long)g);
Assert.IsTrue(h);
}
}
[Test]
public void IncrDifferentSizes()
{
using (var muxer = Create())
{
var db = muxer.GetDatabase();
RedisKey key = Me();
db.KeyDelete(key, CommandFlags.FireAndForget);
int expected = 0;
Incr(db, key, -129019, ref expected);
Incr(db, key, -10023, ref expected);
Incr(db, key, -9933, ref expected);
Incr(db, key, -23, ref expected);
Incr(db, key, -7, ref expected);
Incr(db, key, -1, ref expected);
Incr(db, key, 0, ref expected);
Incr(db, key, 1, ref expected);
Incr(db, key, 9, ref expected);
Incr(db, key, 11, ref expected);
Incr(db, key, 345, ref expected);
Incr(db, key, 4982, ref expected);
Incr(db, key, 13091, ref expected);
Incr(db, key, 324092, ref expected);
Assert.AreNotEqual(0, expected);
var sum = (long)db.StringGet(key);
Assert.AreEqual(expected, sum);
}
}
private void Incr(IDatabase database, RedisKey key, int delta, ref int total)
{
database.StringIncrement(key, delta, CommandFlags.FireAndForget);
total += delta;
}
[Test]
public void WrappedDatabasePrefixIntegration()
{
using (var conn = Create())
{
var db = conn.GetDatabase().WithKeyPrefix("abc");
db.KeyDelete("count");
db.StringIncrement("count");
db.StringIncrement("count");
db.StringIncrement("count");
int count = (int)conn.GetDatabase().StringGet("abccount");
Assert.AreEqual(3, count);
}
}
}
}
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
#if FEATURE_BOOKSLEEVE
using BookSleeve;
#endif
using NUnit.Framework;
using StackExchange.Redis.KeyspaceIsolation;
namespace StackExchange.Redis.Tests
{
[TestFixture]
public class BasicOpsTests : TestBase
{
[Test]
[TestCase(true)]
[TestCase(false)]
public void PingOnce(bool preserveOrder)
{
using (var muxer = Create())
{
muxer.PreserveAsyncOrder = preserveOrder;
var conn = muxer.GetDatabase();
var task = conn.PingAsync();
var duration = muxer.Wait(task);
Console.WriteLine("Ping took: " + duration);
Assert.IsTrue(duration.TotalMilliseconds > 0);
}
}
[Test]
[TestCase(true)]
[TestCase(false)]
public void RapidDispose(bool preserverOrder)
{
RedisKey key = Me();
using (var primary = Create())
{
var conn = primary.GetDatabase();
conn.KeyDelete(key);
for (int i = 0; i < 10; i++)
{
using (var secondary = Create(fail: true))
{
secondary.GetDatabase().StringIncrement(key, flags: CommandFlags.FireAndForget);
}
}
Assert.AreEqual(10, (int)conn.StringGet(key));
}
}
[Test]
[TestCase(true)]
[TestCase(false)]
public void PingMany(bool preserveOrder)
{
using (var muxer = Create())
{
muxer.PreserveAsyncOrder = preserveOrder;
var conn = muxer.GetDatabase();
var tasks = new Task<TimeSpan>[10000];
for (int i = 0; i < tasks.Length; i++)
{
tasks[i] = conn.PingAsync();
}
muxer.WaitAll(tasks);
Assert.IsTrue(tasks[0].Result.TotalMilliseconds > 0);
Assert.IsTrue(tasks[tasks.Length - 1].Result.TotalMilliseconds > 0);
}
}
[Test]
public void GetWithNullKey()
{
using (var muxer = Create())
{
var db = muxer.GetDatabase();
string key = null;
Assert.Throws<ArgumentException>(
() => db.StringGet(key),
"A null key is not valid in this context");
}
}
[Test]
public void SetWithNullKey()
{
using (var muxer = Create())
{
var db = muxer.GetDatabase();
string key = null, value = "abc";
Assert.Throws<ArgumentException>(
() => db.StringSet(key, value),
"A null key is not valid in this context");
}
}
[Test]
public void SetWithNullValue()
{
using (var muxer = Create())
{
var db = muxer.GetDatabase();
string key = Me(), value = null;
db.KeyDelete(key, CommandFlags.FireAndForget);
db.StringSet(key, "abc", flags: CommandFlags.FireAndForget);
Assert.IsTrue(db.KeyExists(key));
db.StringSet(key, value);
var actual = (string)db.StringGet(key);
Assert.IsNull(actual);
Assert.IsFalse(db.KeyExists(key));
}
}
[Test]
public void SetWithDefaultValue()
{
using (var muxer = Create())
{
var db = muxer.GetDatabase();
string key = Me();
var value = default(RedisValue); // this is kinda 0... ish
db.KeyDelete(key, CommandFlags.FireAndForget);
db.StringSet(key, "abc", flags: CommandFlags.FireAndForget);
Assert.IsTrue(db.KeyExists(key));
db.StringSet(key, value);
var actual = (string)db.StringGet(key);
Assert.IsNull(actual);
Assert.IsFalse(db.KeyExists(key));
}
}
[Test]
public void SetWithZeroValue()
{
using (var muxer = Create())
{
var db = muxer.GetDatabase();
string key = Me();
long value = 0;
db.KeyDelete(key, CommandFlags.FireAndForget);
db.StringSet(key, "abc", flags: CommandFlags.FireAndForget);
Assert.IsTrue(db.KeyExists(key));
db.StringSet(key, value);
var actual = (string)db.StringGet(key);
Assert.AreEqual("0", actual);
Assert.IsTrue(db.KeyExists(key));
}
}
[Test]
[TestCase(true)]
[TestCase(false)]
public void GetSetAsync(bool preserveOrder)
{
using (var muxer = Create())
{
muxer.PreserveAsyncOrder = preserveOrder;
var conn = muxer.GetDatabase();
RedisKey key = Me();
var d0 = conn.KeyDeleteAsync(key);
var d1 = conn.KeyDeleteAsync(key);
var g1 = conn.StringGetAsync(key);
var s1 = conn.StringSetAsync(key, "123");
var g2 = conn.StringGetAsync(key);
var d2 = conn.KeyDeleteAsync(key);
muxer.Wait(d0);
Assert.IsFalse(muxer.Wait(d1));
Assert.IsNull((string)muxer.Wait(g1));
Assert.IsTrue(muxer.Wait(g1).IsNull);
muxer.Wait(s1);
Assert.AreEqual("123", (string)muxer.Wait(g2));
Assert.AreEqual(123, (int)muxer.Wait(g2));
Assert.IsFalse(muxer.Wait(g2).IsNull);
Assert.IsTrue(muxer.Wait(d2));
}
}
[Test]
[TestCase(true)]
[TestCase(false)]
public void GetSetSync(bool preserveOrder)
{
using (var muxer = Create())
{
muxer.PreserveAsyncOrder = preserveOrder;
var conn = muxer.GetDatabase();
RedisKey key = Me();
conn.KeyDelete(key);
var d1 = conn.KeyDelete(key);
var g1 = conn.StringGet(key);
conn.StringSet(key, "123");
var g2 = conn.StringGet(key);
var d2 = conn.KeyDelete(key);
Assert.IsFalse(d1);
Assert.IsNull((string)g1);
Assert.IsTrue(g1.IsNull);
Assert.AreEqual("123", (string)g2);
Assert.AreEqual(123, (int)g2);
Assert.IsFalse(g2.IsNull);
Assert.IsTrue(d2);
}
}
[Test]
[TestCase(true, true)]
[TestCase(true, false)]
[TestCase(false, true)]
[TestCase(false, false)]
public void MassiveBulkOpsAsync(bool preserveOrder, bool withContinuation)
{
#if DEBUG
var oldAsyncCompletionCount = ConnectionMultiplexer.GetAsyncCompletionWorkerCount();
#endif
using (var muxer = Create())
{
muxer.PreserveAsyncOrder = preserveOrder;
RedisKey key = "MBOA";
var conn = muxer.GetDatabase();
muxer.Wait(conn.PingAsync());
#if DNXCORE50
int number = 0;
#endif
Action<Task> nonTrivial = delegate
{
#if !DNXCORE50
Thread.SpinWait(5);
#else
for (int i = 0; i < 50; i++)
{
number++;
}
#endif
};
var watch = Stopwatch.StartNew();
for (int i = 0; i <= AsyncOpsQty; i++)
{
var t = conn.StringSetAsync(key, i);
if (withContinuation) t.ContinueWith(nonTrivial);
}
int val = (int)muxer.Wait(conn.StringGetAsync(key));
Assert.AreEqual(AsyncOpsQty, val);
watch.Stop();
Console.WriteLine("{2}: Time for {0} ops: {1}ms ({3}, {4}); ops/s: {5}", AsyncOpsQty, watch.ElapsedMilliseconds, Me(),
withContinuation ? "with continuation" : "no continuation", preserveOrder ? "preserve order" : "any order",
AsyncOpsQty / watch.Elapsed.TotalSeconds);
#if DEBUG
Console.WriteLine("Async completion workers: " + (ConnectionMultiplexer.GetAsyncCompletionWorkerCount() - oldAsyncCompletionCount));
#endif
}
}
[Test]
[TestCase(false, false)]
[TestCase(true, true)]
[TestCase(true, false)]
public void GetWithExpiry(bool exists, bool hasExpiry)
{
using(var conn = Create())
{
var db = conn.GetDatabase();
RedisKey key = Me();
db.KeyDelete(key);
if (exists)
{
if (hasExpiry)
db.StringSet(key, "val", TimeSpan.FromMinutes(5));
else
db.StringSet(key, "val");
}
var async = db.StringGetWithExpiryAsync(key);
var syncResult = db.StringGetWithExpiry(key);
var asyncResult = db.Wait(async);
if(exists)
{
Assert.AreEqual("val", (string)asyncResult.Value);
Assert.AreEqual(hasExpiry, asyncResult.Expiry.HasValue);
if (hasExpiry) Assert.IsTrue(asyncResult.Expiry.Value.TotalMinutes >= 4.9 && asyncResult.Expiry.Value.TotalMinutes <= 5);
Assert.AreEqual("val", (string)syncResult.Value);
Assert.AreEqual(hasExpiry, syncResult.Expiry.HasValue);
if (hasExpiry) Assert.IsTrue(syncResult.Expiry.Value.TotalMinutes >= 4.9 && syncResult.Expiry.Value.TotalMinutes <= 5);
}
else
{
Assert.IsTrue(asyncResult.Value.IsNull);
Assert.IsFalse(asyncResult.Expiry.HasValue);
Assert.IsTrue(syncResult.Value.IsNull);
Assert.IsFalse(syncResult.Expiry.HasValue);
}
}
}
[Test]
public void GetWithExpiryWrongTypeAsync()
{
using (var conn = Create())
{
var db = conn.GetDatabase();
RedisKey key = Me();
db.KeyDelete(key);
db.SetAdd(key, "abc");
Assert.Throws<RedisServerException>(() =>
{
try
{
var async = db.Wait(db.StringGetWithExpiryAsync(key));
}
catch (AggregateException ex)
{
throw ex.InnerExceptions[0];
}
Assert.Fail();
},
"A null key is not valid in this context");
}
}
[Test]
public void GetWithExpiryWrongTypeSync()
{
Assert.Throws<RedisServerException>(() =>
{
using (var conn = Create())
{
var db = conn.GetDatabase();
RedisKey key = Me();
db.KeyDelete(key);
db.SetAdd(key, "abc");
db.StringGetWithExpiry(key);
Assert.Fail();
}
},
"WRONGTYPE Operation against a key holding the wrong kind of value");
}
#if FEATURE_BOOKSLEEVE
[Test]
[TestCase(true, true, ResultCompletionMode.ConcurrentIfContinuation)]
[TestCase(true, false, ResultCompletionMode.ConcurrentIfContinuation)]
[TestCase(false, true, ResultCompletionMode.ConcurrentIfContinuation)]
[TestCase(false, false, ResultCompletionMode.ConcurrentIfContinuation)]
[TestCase(true, true, ResultCompletionMode.Concurrent)]
[TestCase(true, false, ResultCompletionMode.Concurrent)]
[TestCase(false, true, ResultCompletionMode.Concurrent)]
[TestCase(false, false, ResultCompletionMode.Concurrent)]
[TestCase(true, true, ResultCompletionMode.PreserveOrder)]
[TestCase(true, false, ResultCompletionMode.PreserveOrder)]
[TestCase(false, true, ResultCompletionMode.PreserveOrder)]
[TestCase(false, false, ResultCompletionMode.PreserveOrder)]
public void MassiveBulkOpsAsyncOldStyle(bool withContinuation, bool suspendFlush, ResultCompletionMode completionMode)
{
using (var conn = GetOldStyleConnection())
{
const int db = 0;
string key = "MBOQ";
conn.CompletionMode = completionMode;
conn.Wait(conn.Server.Ping());
Action<Task> nonTrivial = delegate
{
Thread.SpinWait(5);
};
var watch = Stopwatch.StartNew();
if (suspendFlush) conn.SuspendFlush();
try
{
for (int i = 0; i <= AsyncOpsQty; i++)
{
var t = conn.Strings.Set(db, key, i);
if (withContinuation) t.ContinueWith(nonTrivial);
}
} finally
{
if (suspendFlush) conn.ResumeFlush();
}
int val = (int)conn.Wait(conn.Strings.GetInt64(db, key));
Assert.AreEqual(AsyncOpsQty, val);
watch.Stop();
Console.WriteLine("{2}: Time for {0} ops: {1}ms ({3}, {4}, {5}); ops/s: {6}", AsyncOpsQty, watch.ElapsedMilliseconds, Me(),
withContinuation ? "with continuation" : "no continuation",
suspendFlush ? "suspend flush" : "flush at whim",
completionMode, AsyncOpsQty / watch.Elapsed.TotalSeconds);
}
}
#endif
[Test]
[TestCase(true, 1)]
[TestCase(false, 1)]
[TestCase(true, 5)]
[TestCase(false, 5)]
[TestCase(true, 10)]
[TestCase(false, 10)]
[TestCase(true, 50)]
[TestCase(false, 50)]
public void MassiveBulkOpsSync(bool preserveOrder, int threads)
{
int workPerThread = SyncOpsQty / threads;
using (var muxer = Create())
{
muxer.PreserveAsyncOrder = preserveOrder;
RedisKey key = "MBOS";
var conn = muxer.GetDatabase();
conn.KeyDelete(key);
#if DEBUG
long oldAlloc = ConnectionMultiplexer.GetResultBoxAllocationCount();
long oldWorkerCount = ConnectionMultiplexer.GetAsyncCompletionWorkerCount();
#endif
var timeTaken = RunConcurrent(delegate
{
for (int i = 0; i < workPerThread; i++)
{
conn.StringIncrement(key);
}
}, threads);
int val = (int)conn.StringGet(key);
Assert.AreEqual(workPerThread * threads, val);
Console.WriteLine("{2}: Time for {0} ops on {4} threads: {1}ms ({3}); ops/s: {5}",
threads * workPerThread, timeTaken.TotalMilliseconds, Me()
, preserveOrder ? "preserve order" : "any order", threads, (workPerThread * threads) / timeTaken.TotalSeconds);
#if DEBUG
long newAlloc = ConnectionMultiplexer.GetResultBoxAllocationCount();
long newWorkerCount = ConnectionMultiplexer.GetAsyncCompletionWorkerCount();
Console.WriteLine("ResultBox allocations: {0}; workers {1}", newAlloc - oldAlloc, newWorkerCount - oldWorkerCount);
Assert.IsTrue(newAlloc - oldAlloc <= 2 * threads, "number of box allocations");
#endif
}
}
#if FEATURE_BOOKSLEEVE
[Test]
[TestCase(ResultCompletionMode.Concurrent, 1)]
[TestCase(ResultCompletionMode.ConcurrentIfContinuation, 1)]
[TestCase(ResultCompletionMode.PreserveOrder, 1)]
[TestCase(ResultCompletionMode.Concurrent, 5)]
[TestCase(ResultCompletionMode.ConcurrentIfContinuation, 5)]
[TestCase(ResultCompletionMode.PreserveOrder, 5)]
[TestCase(ResultCompletionMode.Concurrent, 10)]
[TestCase(ResultCompletionMode.ConcurrentIfContinuation, 10)]
[TestCase(ResultCompletionMode.PreserveOrder, 10)]
[TestCase(ResultCompletionMode.Concurrent, 50)]
[TestCase(ResultCompletionMode.ConcurrentIfContinuation, 50)]
[TestCase(ResultCompletionMode.PreserveOrder, 50)]
public void MassiveBulkOpsSyncOldStyle(ResultCompletionMode completionMode, int threads)
{
int workPerThread = SyncOpsQty / threads;
using (var conn = GetOldStyleConnection())
{
const int db = 0;
string key = "MBOQ";
conn.CompletionMode = completionMode;
conn.Wait(conn.Keys.Remove(db, key));
var timeTaken = RunConcurrent(delegate
{
for (int i = 0; i < workPerThread; i++)
{
conn.Wait(conn.Strings.Increment(db, key));
}
}, threads);
int val = (int)conn.Wait(conn.Strings.GetInt64(db, key));
Assert.AreEqual(workPerThread * threads, val);
Console.WriteLine("{2}: Time for {0} ops on {4} threads: {1}ms ({3}); ops/s: {5}", workPerThread * threads, timeTaken.TotalMilliseconds, Me(),
completionMode, threads, (workPerThread * threads) / timeTaken.TotalSeconds);
}
}
#endif
[Test]
[TestCase(true, 1)]
[TestCase(false, 1)]
[TestCase(true, 5)]
[TestCase(false, 5)]
public void MassiveBulkOpsFireAndForget(bool preserveOrder, int threads)
{
using (var muxer = Create())
{
muxer.PreserveAsyncOrder = preserveOrder;
#if DEBUG
long oldAlloc = ConnectionMultiplexer.GetResultBoxAllocationCount();
#endif
RedisKey key = "MBOF";
var conn = muxer.GetDatabase();
conn.Ping();
conn.KeyDelete(key, CommandFlags.FireAndForget);
int perThread = AsyncOpsQty / threads;
var elapsed = RunConcurrent(delegate
{
for (int i = 0; i < perThread; i++)
{
conn.StringIncrement(key, flags: CommandFlags.FireAndForget);
}
conn.Ping();
}, threads);
var val = (long)conn.StringGet(key);
Assert.AreEqual(perThread * threads, val);
Console.WriteLine("{2}: Time for {0} ops over {5} threads: {1:###,###}ms ({3}); ops/s: {4:###,###,##0}",
val, elapsed.TotalMilliseconds, Me(),
preserveOrder ? "preserve order" : "any order",
val / elapsed.TotalSeconds, threads);
#if DEBUG
long newAlloc = ConnectionMultiplexer.GetResultBoxAllocationCount();
Console.WriteLine("ResultBox allocations: {0}",
newAlloc - oldAlloc);
Assert.IsTrue(newAlloc - oldAlloc <= 4);
#endif
}
}
#if DEBUG
[Test]
[TestCase(true)]
[TestCase(false)]
public void TestQuit(bool preserveOrder)
{
SetExpectedAmbientFailureCount(1);
using (var muxer = Create(allowAdmin: true))
{
muxer.PreserveAsyncOrder = preserveOrder;
var db = muxer.GetDatabase();
string key = Guid.NewGuid().ToString();
db.KeyDelete(key, CommandFlags.FireAndForget);
db.StringSet(key, key, flags: CommandFlags.FireAndForget);
GetServer(muxer).Quit(CommandFlags.FireAndForget);
var watch = Stopwatch.StartNew();
try
{
db.Ping();
Assert.Fail();
}
catch (RedisConnectionException) { }
watch.Stop();
Console.WriteLine("Time to notice quit: {0}ms ({1})", watch.ElapsedMilliseconds,
preserveOrder ? "preserve order" : "any order");
Thread.Sleep(20);
Debug.WriteLine("Pinging...");
Assert.AreEqual(key, (string)db.StringGet(key));
}
}
[Test]
[TestCase(true)]
[TestCase(false)]
public void TestSevered(bool preserveOrder)
{
SetExpectedAmbientFailureCount(2);
using (var muxer = Create(allowAdmin: true))
{
muxer.PreserveAsyncOrder = preserveOrder;
var db = muxer.GetDatabase();
string key = Guid.NewGuid().ToString();
db.KeyDelete(key, CommandFlags.FireAndForget);
db.StringSet(key, key, flags: CommandFlags.FireAndForget);
GetServer(muxer).SimulateConnectionFailure();
var watch = Stopwatch.StartNew();
db.Ping();
watch.Stop();
Console.WriteLine("Time to re-establish: {0}ms ({1})", watch.ElapsedMilliseconds,
preserveOrder ? "preserve order" : "any order");
Thread.Sleep(20);
Debug.WriteLine("Pinging...");
Assert.AreEqual(key, (string)db.StringGet(key));
}
}
#endif
[Test]
[TestCase(true)]
[TestCase(false)]
public void IncrAsync(bool preserveOrder)
{
using (var muxer = Create())
{
muxer.PreserveAsyncOrder = preserveOrder;
var conn = muxer.GetDatabase();
RedisKey key = Me();
conn.KeyDelete(key, CommandFlags.FireAndForget);
var nix = conn.KeyExistsAsync(key);
var a = conn.StringGetAsync(key);
var b = conn.StringIncrementAsync(key);
var c = conn.StringGetAsync(key);
var d = conn.StringIncrementAsync(key, 10);
var e = conn.StringGetAsync(key);
var f = conn.StringDecrementAsync(key, 11);
var g = conn.StringGetAsync(key);
var h = conn.KeyExistsAsync(key);
Assert.IsFalse(muxer.Wait(nix));
Assert.IsTrue(muxer.Wait(a).IsNull);
Assert.AreEqual(0, (long)muxer.Wait(a));
Assert.AreEqual(1, muxer.Wait(b));
Assert.AreEqual(1, (long)muxer.Wait(c));
Assert.AreEqual(11, muxer.Wait(d));
Assert.AreEqual(11, (long)muxer.Wait(e));
Assert.AreEqual(0, muxer.Wait(f));
Assert.AreEqual(0, (long)muxer.Wait(g));
Assert.IsTrue(muxer.Wait(h));
}
}
[Test]
[TestCase(true)]
[TestCase(false)]
public void IncrSync(bool preserveOrder)
{
using (var muxer = Create())
{
muxer.PreserveAsyncOrder = preserveOrder;
var conn = muxer.GetDatabase();
RedisKey key = Me();
conn.KeyDelete(key, CommandFlags.FireAndForget);
var nix = conn.KeyExists(key);
var a = conn.StringGet(key);
var b = conn.StringIncrement(key);
var c = conn.StringGet(key);
var d = conn.StringIncrement(key, 10);
var e = conn.StringGet(key);
var f = conn.StringDecrement(key, 11);
var g = conn.StringGet(key);
var h = conn.KeyExists(key);
Assert.IsFalse(nix);
Assert.IsTrue(a.IsNull);
Assert.AreEqual(0, (long)a);
Assert.AreEqual(1, b);
Assert.AreEqual(1, (long)c);
Assert.AreEqual(11, d);
Assert.AreEqual(11, (long)e);
Assert.AreEqual(0, f);
Assert.AreEqual(0, (long)g);
Assert.IsTrue(h);
}
}
[Test]
public void IncrDifferentSizes()
{
using (var muxer = Create())
{
var db = muxer.GetDatabase();
RedisKey key = Me();
db.KeyDelete(key, CommandFlags.FireAndForget);
int expected = 0;
Incr(db, key, -129019, ref expected);
Incr(db, key, -10023, ref expected);
Incr(db, key, -9933, ref expected);
Incr(db, key, -23, ref expected);
Incr(db, key, -7, ref expected);
Incr(db, key, -1, ref expected);
Incr(db, key, 0, ref expected);
Incr(db, key, 1, ref expected);
Incr(db, key, 9, ref expected);
Incr(db, key, 11, ref expected);
Incr(db, key, 345, ref expected);
Incr(db, key, 4982, ref expected);
Incr(db, key, 13091, ref expected);
Incr(db, key, 324092, ref expected);
Assert.AreNotEqual(0, expected);
var sum = (long)db.StringGet(key);
Assert.AreEqual(expected, sum);
}
}
private void Incr(IDatabase database, RedisKey key, int delta, ref int total)
{
database.StringIncrement(key, delta, CommandFlags.FireAndForget);
total += delta;
}
[Test]
public void WrappedDatabasePrefixIntegration()
{
using (var conn = Create())
{
var db = conn.GetDatabase().WithKeyPrefix("abc");
db.KeyDelete("count");
db.StringIncrement("count");
db.StringIncrement("count");
db.StringIncrement("count");
int count = (int)conn.GetDatabase().StringGet("abccount");
Assert.AreEqual(3, count);
}
}
}
}
using System;
using NUnit.Framework;
using StackExchange.Redis.KeyspaceIsolation;
namespace StackExchange.Redis.Tests
{
[TestFixture]
public class WithKeyPrefixTests : TestBase
{
[Test]
public void BlankPrefixYieldsSame_Bytes()
{
using (var conn = Create())
{
var raw = conn.GetDatabase(1);
var prefixed = raw.WithKeyPrefix(new byte[0]);
Assert.AreSame(raw, prefixed);
}
}
[Test]
public void BlankPrefixYieldsSame_String()
{
using (var conn = Create())
{
var raw = conn.GetDatabase(1);
var prefixed = raw.WithKeyPrefix("");
Assert.AreSame(raw, prefixed);
}
}
[Test]
public void NullPrefixIsError_Bytes()
{
Assert.Throws<ArgumentNullException>(() => {
using (var conn = Create())
{
var raw = conn.GetDatabase(1);
var prefixed = raw.WithKeyPrefix((byte[])null);
}
});
}
[Test]
public void NullPrefixIsError_String()
{
Assert.Throws<ArgumentNullException>(() => {
using (var conn = Create())
{
var raw = conn.GetDatabase(1);
var prefixed = raw.WithKeyPrefix((string)null);
}
});
}
[Test]
[TestCase("abc")]
[TestCase("")]
[TestCase(null)]
public void NullDatabaseIsError(string prefix)
{
Assert.Throws<ArgumentNullException>(() => {
IDatabase raw = null;
var prefixed = raw.WithKeyPrefix(prefix);
});
}
[Test]
public void BasicSmokeTest()
{
using(var conn = Create())
{
var raw = conn.GetDatabase(1);
var foo = raw.WithKeyPrefix("foo");
var foobar = foo.WithKeyPrefix("bar");
string key = Me();
string s = Guid.NewGuid().ToString(), t = Guid.NewGuid().ToString();
foo.StringSet(key, s);
var val = (string)foo.StringGet(key);
Assert.AreEqual(s, val); // fooBasicSmokeTest
foobar.StringSet(key, t);
val = (string)foobar.StringGet(key);
Assert.AreEqual(t, val); // foobarBasicSmokeTest
val = (string)foo.StringGet("bar" + key);
Assert.AreEqual(t, val); // foobarBasicSmokeTest
val = (string)raw.StringGet("foo" + key);
Assert.AreEqual(s, val); // fooBasicSmokeTest
val = (string)raw.StringGet("foobar" + key);
Assert.AreEqual(t, val); // foobarBasicSmokeTest
}
}
[Test]
public void ConditionTest()
{
using(var conn = Create())
{
var raw = conn.GetDatabase(2);
var foo = raw.WithKeyPrefix("tran:");
raw.KeyDelete("tran:abc");
raw.KeyDelete("tran:i");
// execute while key exists
raw.StringSet("tran:abc", "def");
var tran = foo.CreateTransaction();
tran.AddCondition(Condition.KeyExists("abc"));
tran.StringIncrementAsync("i");
tran.Execute();
int i = (int)raw.StringGet("tran:i");
Assert.AreEqual(1, i);
// repeat without key
raw.KeyDelete("tran:abc");
tran = foo.CreateTransaction();
tran.AddCondition(Condition.KeyExists("abc"));
tran.StringIncrementAsync("i");
tran.Execute();
i = (int)raw.StringGet("tran:i");
Assert.AreEqual(1, i);
}
}
}
}
using System;
using NUnit.Framework;
using StackExchange.Redis.KeyspaceIsolation;
namespace StackExchange.Redis.Tests
{
[TestFixture]
public class WithKeyPrefixTests : TestBase
{
[Test]
public void BlankPrefixYieldsSame_Bytes()
{
using (var conn = Create())
{
var raw = conn.GetDatabase(1);
var prefixed = raw.WithKeyPrefix(new byte[0]);
Assert.AreSame(raw, prefixed);
}
}
[Test]
public void BlankPrefixYieldsSame_String()
{
using (var conn = Create())
{
var raw = conn.GetDatabase(1);
var prefixed = raw.WithKeyPrefix("");
Assert.AreSame(raw, prefixed);
}
}
[Test]
public void NullPrefixIsError_Bytes()
{
Assert.Throws<ArgumentNullException>(() => {
using (var conn = Create())
{
var raw = conn.GetDatabase(1);
var prefixed = raw.WithKeyPrefix((byte[])null);
}
});
}
[Test]
public void NullPrefixIsError_String()
{
Assert.Throws<ArgumentNullException>(() => {
using (var conn = Create())
{
var raw = conn.GetDatabase(1);
var prefixed = raw.WithKeyPrefix((string)null);
}
});
}
[Test]
[TestCase("abc")]
[TestCase("")]
[TestCase(null)]
public void NullDatabaseIsError(string prefix)
{
Assert.Throws<ArgumentNullException>(() => {
IDatabase raw = null;
var prefixed = raw.WithKeyPrefix(prefix);
});
}
[Test]
public void BasicSmokeTest()
{
using(var conn = Create())
{
var raw = conn.GetDatabase(1);
var foo = raw.WithKeyPrefix("foo");
var foobar = foo.WithKeyPrefix("bar");
string key = Me();
string s = Guid.NewGuid().ToString(), t = Guid.NewGuid().ToString();
foo.StringSet(key, s);
var val = (string)foo.StringGet(key);
Assert.AreEqual(s, val); // fooBasicSmokeTest
foobar.StringSet(key, t);
val = (string)foobar.StringGet(key);
Assert.AreEqual(t, val); // foobarBasicSmokeTest
val = (string)foo.StringGet("bar" + key);
Assert.AreEqual(t, val); // foobarBasicSmokeTest
val = (string)raw.StringGet("foo" + key);
Assert.AreEqual(s, val); // fooBasicSmokeTest
val = (string)raw.StringGet("foobar" + key);
Assert.AreEqual(t, val); // foobarBasicSmokeTest
}
}
[Test]
public void ConditionTest()
{
using(var conn = Create())
{
var raw = conn.GetDatabase(2);
var foo = raw.WithKeyPrefix("tran:");
raw.KeyDelete("tran:abc");
raw.KeyDelete("tran:i");
// execute while key exists
raw.StringSet("tran:abc", "def");
var tran = foo.CreateTransaction();
tran.AddCondition(Condition.KeyExists("abc"));
tran.StringIncrementAsync("i");
tran.Execute();
int i = (int)raw.StringGet("tran:i");
Assert.AreEqual(1, i);
// repeat without key
raw.KeyDelete("tran:abc");
tran = foo.CreateTransaction();
tran.AddCondition(Condition.KeyExists("abc"));
tran.StringIncrementAsync("i");
tran.Execute();
i = (int)raw.StringGet("tran:i");
Assert.AreEqual(1, i);
}
}
}
}
......@@ -16,7 +16,6 @@ public sealed class WrapperBaseTests
private Mock<IDatabaseAsync> mock;
private WrapperBase<IDatabaseAsync> wrapper;
//[TestFixtureSetUp]
[OneTimeSetUp]
public void Initialize()
{
......@@ -891,4 +890,4 @@ public void StringSetRangeAsync()
}
}
}
#endif
\ No newline at end of file
#endif
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{EBF46088-E318-4D32-9EFB-01EF130A4554}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>StackExchange.Redis</RootNamespace>
<AssemblyName>StackExchange.Redis.StrongName</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin.snk\Debug\</OutputPath>
<DefineConstants>TRACE;DEBUG;STRONG_NAME FEATURE_SERIALIZATION FEATURE_SOCKET_MODE_POLL</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DocumentationFile>bin.snk\Debug\StackExchange.Redis.StrongName.xml</DocumentationFile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin.snk\Release\</OutputPath>
<DefineConstants>TRACE;STRONG_NAME FEATURE_SERIALIZATION FEATURE_SOCKET_MODE_POLL</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DocumentationFile>bin.snk\Release\StackExchange.Redis.StrongName.xml</DocumentationFile>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Verbose|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin.snk\Verbose\</OutputPath>
<DefineConstants>TRACE;DEBUG;VERBOSE STRONG_NAME FEATURE_SERIALIZATION FEATURE_SOCKET_MODE_POLL</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DocumentationFile>bin.snk\Verbose\StackExchange.Redis.StrongName.xml</DocumentationFile>
<DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<UseVSHostingProcess>false</UseVSHostingProcess>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Log Output|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin.snk\LogOutput\</OutputPath>
<DefineConstants>TRACE;DEBUG;LOGOUTPUT STRONG_NAME FEATURE_SERIALIZATION FEATURE_SOCKET_MODE_POLL</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DocumentationFile>bin.snk\LogOutput\StackExchange.Redis.StrongName.xml</DocumentationFile>
<DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup>
<SignAssembly>true</SignAssembly>
</PropertyGroup>
<PropertyGroup>
<AssemblyOriginatorKeyFile>StackExchange.Redis.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Mono|AnyCPU'">
<OutputPath>bin\Mono\</OutputPath>
<DefineConstants>TRACE;STRONG_NAME FEATURE_SERIALIZATION</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DocumentationFile>bin.snk\Release\StackExchange.Redis.StrongName.xml</DocumentationFile>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.IO.Compression" />
</ItemGroup>
<ItemGroup>
<Compile Include="StackExchange\Redis\Aggregate.cs" />
<Compile Include="StackExchange\Redis\ClientType.cs" />
<Compile Include="StackExchange\Redis\Compat\ConvertHelper.cs" />
<Compile Include="StackExchange\Redis\Compat\VolatileWrapper.cs" />
<Compile Include="StackExchange\Redis\ConcurrentProfileStorageCollection.cs" />
<Compile Include="StackExchange\Redis\ConnectionMultiplexer.Profiling.cs">
<DependentUpon>ConnectionMultiplexer.cs</DependentUpon>
</Compile>
<Compile Include="StackExchange\Redis\ExtensionMethods.cs" />
<Compile Include="StackExchange\Redis\HashEntry.cs" />
<Compile Include="StackExchange\Redis\IConnectionMultiplexer.cs" />
<Compile Include="StackExchange\Redis\InternalErrorEventArgs.cs" />
<Compile Include="StackExchange\Redis\InternalRegexCompiledOption.cs" />
<Compile Include="StackExchange\Redis\IProfiler.cs" />
<Compile Include="StackExchange\Redis\MigrateOptions.cs" />
<Compile Include="StackExchange\Redis\ProfileContextTracker.cs" />
<Compile Include="StackExchange\Redis\ProfileStorage.cs" />
<Compile Include="StackExchange\Redis\LuaScript.cs" />
<Compile Include="StackExchange\Redis\RedisChannel.cs" />
<Compile Include="StackExchange\Redis\Bitwise.cs" />
<Compile Include="StackExchange\Redis\ClientFlags.cs" />
<Compile Include="StackExchange\Redis\ClientInfo.cs" />
<Compile Include="StackExchange\Redis\ClusterConfiguration.cs" />
<Compile Include="StackExchange\Redis\CommandTrace.cs" />
<Compile Include="StackExchange\Redis\Condition.cs" />
<Compile Include="StackExchange\Redis\ConfigurationOptions.cs" />
<Compile Include="StackExchange\Redis\ConnectionCounters.cs" />
<Compile Include="StackExchange\Redis\ConnectionFailedEventArgs.cs" />
<Compile Include="StackExchange\Redis\ConnectionFailureType.cs" />
<Compile Include="StackExchange\Redis\ConnectionMultiplexer.ReaderWriter.cs">
<DependentUpon>ConnectionMultiplexer.cs</DependentUpon>
</Compile>
<Compile Include="StackExchange\Redis\ConnectionType.cs" />
<Compile Include="StackExchange\Redis\DebuggingAids.cs" />
<Compile Include="StackExchange\Redis\EndPointCollection.cs" />
<Compile Include="StackExchange\Redis\EndPointEventArgs.cs" />
<Compile Include="StackExchange\Redis\ExceptionFactory.cs" />
<Compile Include="StackExchange\Redis\Exclude.cs" />
<Compile Include="StackExchange\Redis\ExportOptions.cs" />
<Compile Include="StackExchange\Redis\Format.cs" />
<Compile Include="StackExchange\Redis\IBatch.cs" />
<Compile Include="StackExchange\Redis\IMultiMessage.cs" />
<Compile Include="StackExchange\Redis\Order.cs" />
<Compile Include="StackExchange\Redis\RedisBatch.cs" />
<Compile Include="StackExchange\Redis\RedisCommand.cs" />
<Compile Include="StackExchange\Redis\RedisErrorEventArgs.cs" />
<Compile Include="StackExchange\Redis\HashSlotMovedEventArgs.cs" />
<Compile Include="StackExchange\Redis\ITransaction.cs" />
<Compile Include="StackExchange\Redis\IRedis.cs" />
<Compile Include="StackExchange\Redis\IRedisAsync.cs" />
<Compile Include="StackExchange\Redis\IDatabase.cs" />
<Compile Include="StackExchange\Redis\IDatabaseAsync.cs" />
<Compile Include="StackExchange\Redis\IServer.cs" />
<Compile Include="StackExchange\Redis\ISubscriber.cs" />
<Compile Include="StackExchange\Redis\MessageCompletable.cs" />
<Compile Include="StackExchange\Redis\RedisBase.cs" />
<Compile Include="StackExchange\Redis\CommandFlags.cs" />
<Compile Include="StackExchange\Redis\CommandMap.cs" />
<Compile Include="StackExchange\Redis\CompletionManager.cs" />
<Compile Include="StackExchange\Redis\ConnectionMultiplexer.cs" />
<Compile Include="StackExchange\Redis\CompletedDefaultTask.cs" />
<Compile Include="StackExchange\Redis\ICompletable.cs" />
<Compile Include="StackExchange\Redis\LoggingTextStream.cs" />
<Compile Include="StackExchange\Redis\PhysicalBridge.cs" />
<Compile Include="StackExchange\Redis\Message.cs" />
<Compile Include="StackExchange\Redis\MessageQueue.cs" />
<Compile Include="StackExchange\Redis\PhysicalConnection.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="StackExchange\Redis\RedisResult.cs" />
<Compile Include="StackExchange\Redis\RedisTransaction.cs" />
<Compile Include="StackExchange\Redis\RedisDatabase.cs" />
<Compile Include="StackExchange\Redis\RedisFeatures.cs" />
<Compile Include="StackExchange\Redis\RedisKey.cs" />
<Compile Include="StackExchange\Redis\RedisLiterals.cs" />
<Compile Include="StackExchange\Redis\RedisServer.cs" />
<Compile Include="StackExchange\Redis\RedisType.cs" />
<Compile Include="StackExchange\Redis\RedisValue.cs" />
<Compile Include="StackExchange\Redis\ReplicationChangeOptions.cs" />
<Compile Include="StackExchange\Redis\RawResult.cs" />
<Compile Include="StackExchange\Redis\ResultBox.cs" />
<Compile Include="StackExchange\Redis\ResultProcessor.cs" />
<Compile Include="StackExchange\Redis\RedisSubscriber.cs" />
<Compile Include="StackExchange\Redis\ResultType.cs" />
<Compile Include="StackExchange\Redis\ScriptParameterMapper.cs" />
<Compile Include="StackExchange\Redis\ServerCounters.cs" />
<Compile Include="StackExchange\Redis\ServerEndPoint.cs" />
<Compile Include="StackExchange\Redis\ServerSelectionStrategy.cs" />
<Compile Include="StackExchange\Redis\ServerType.cs" />
<Compile Include="StackExchange\Redis\SetOperation.cs" />
<Compile Include="StackExchange\Redis\SocketManager.cs" />
<Compile Include="StackExchange\Redis\SocketManager.NoPoll.cs">
<DependentUpon>SocketManager.cs</DependentUpon>
</Compile>
<Compile Include="StackExchange\Redis\SortedSetEntry.cs" />
<Compile Include="StackExchange\Redis\SortType.cs" />
<Compile Include="StackExchange\Redis\StringSplits.cs" />
<Compile Include="StackExchange\Redis\TaskSource.cs" />
<Compile Include="StackExchange\Redis\When.cs" />
<Compile Include="StackExchange\Redis\ShutdownMode.cs" />
<Compile Include="StackExchange\Redis\SaveType.cs" />
<Compile Include="StackExchange\Redis\KeyspaceIsolation\BatchWrapper.cs" />
<Compile Include="StackExchange\Redis\KeyspaceIsolation\DatabaseExtension.cs" />
<Compile Include="StackExchange\Redis\KeyspaceIsolation\DatabaseWrapper.cs" />
<Compile Include="StackExchange\Redis\KeyspaceIsolation\TransactionWrapper.cs" />
<Compile Include="StackExchange\Redis\KeyspaceIsolation\WrapperBase.cs" />
</ItemGroup>
<ItemGroup>
<Compile Include="StackExchange\Redis\SocketManager.Poll.cs">
<DependentUpon>SocketManager.cs</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<None Include="StackExchange.Redis.snk" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{EBF46088-E318-4D32-9EFB-01EF130A4554}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>StackExchange.Redis</RootNamespace>
<AssemblyName>StackExchange.Redis.StrongName</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin.snk\Debug\</OutputPath>
<DefineConstants>TRACE;DEBUG;STRONG_NAME FEATURE_SERIALIZATION FEATURE_SOCKET_MODE_POLL</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DocumentationFile>bin.snk\Debug\StackExchange.Redis.StrongName.xml</DocumentationFile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin.snk\Release\</OutputPath>
<DefineConstants>TRACE;STRONG_NAME FEATURE_SERIALIZATION FEATURE_SOCKET_MODE_POLL</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DocumentationFile>bin.snk\Release\StackExchange.Redis.StrongName.xml</DocumentationFile>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Verbose|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin.snk\Verbose\</OutputPath>
<DefineConstants>TRACE;DEBUG;VERBOSE STRONG_NAME FEATURE_SERIALIZATION FEATURE_SOCKET_MODE_POLL</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DocumentationFile>bin.snk\Verbose\StackExchange.Redis.StrongName.xml</DocumentationFile>
<DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<UseVSHostingProcess>false</UseVSHostingProcess>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Log Output|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin.snk\LogOutput\</OutputPath>
<DefineConstants>TRACE;DEBUG;LOGOUTPUT STRONG_NAME FEATURE_SERIALIZATION FEATURE_SOCKET_MODE_POLL</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DocumentationFile>bin.snk\LogOutput\StackExchange.Redis.StrongName.xml</DocumentationFile>
<DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup>
<SignAssembly>true</SignAssembly>
</PropertyGroup>
<PropertyGroup>
<AssemblyOriginatorKeyFile>StackExchange.Redis.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Mono|AnyCPU'">
<OutputPath>bin\Mono\</OutputPath>
<DefineConstants>TRACE;STRONG_NAME FEATURE_SERIALIZATION</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DocumentationFile>bin.snk\Release\StackExchange.Redis.StrongName.xml</DocumentationFile>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.IO.Compression" />
</ItemGroup>
<ItemGroup>
<Compile Include="StackExchange\Redis\Aggregate.cs" />
<Compile Include="StackExchange\Redis\ClientType.cs" />
<Compile Include="StackExchange\Redis\Compat\ConvertHelper.cs" />
<Compile Include="StackExchange\Redis\Compat\VolatileWrapper.cs" />
<Compile Include="StackExchange\Redis\ConcurrentProfileStorageCollection.cs" />
<Compile Include="StackExchange\Redis\ConnectionMultiplexer.Profiling.cs">
<DependentUpon>ConnectionMultiplexer.cs</DependentUpon>
</Compile>
<Compile Include="StackExchange\Redis\ExtensionMethods.cs" />
<Compile Include="StackExchange\Redis\HashEntry.cs" />
<Compile Include="StackExchange\Redis\IConnectionMultiplexer.cs" />
<Compile Include="StackExchange\Redis\InternalErrorEventArgs.cs" />
<Compile Include="StackExchange\Redis\InternalRegexCompiledOption.cs" />
<Compile Include="StackExchange\Redis\IProfiler.cs" />
<Compile Include="StackExchange\Redis\MigrateOptions.cs" />
<Compile Include="StackExchange\Redis\ProfileContextTracker.cs" />
<Compile Include="StackExchange\Redis\ProfileStorage.cs" />
<Compile Include="StackExchange\Redis\LuaScript.cs" />
<Compile Include="StackExchange\Redis\RedisChannel.cs" />
<Compile Include="StackExchange\Redis\Bitwise.cs" />
<Compile Include="StackExchange\Redis\ClientFlags.cs" />
<Compile Include="StackExchange\Redis\ClientInfo.cs" />
<Compile Include="StackExchange\Redis\ClusterConfiguration.cs" />
<Compile Include="StackExchange\Redis\CommandTrace.cs" />
<Compile Include="StackExchange\Redis\Condition.cs" />
<Compile Include="StackExchange\Redis\ConfigurationOptions.cs" />
<Compile Include="StackExchange\Redis\ConnectionCounters.cs" />
<Compile Include="StackExchange\Redis\ConnectionFailedEventArgs.cs" />
<Compile Include="StackExchange\Redis\ConnectionFailureType.cs" />
<Compile Include="StackExchange\Redis\ConnectionMultiplexer.ReaderWriter.cs">
<DependentUpon>ConnectionMultiplexer.cs</DependentUpon>
</Compile>
<Compile Include="StackExchange\Redis\ConnectionType.cs" />
<Compile Include="StackExchange\Redis\DebuggingAids.cs" />
<Compile Include="StackExchange\Redis\EndPointCollection.cs" />
<Compile Include="StackExchange\Redis\EndPointEventArgs.cs" />
<Compile Include="StackExchange\Redis\ExceptionFactory.cs" />
<Compile Include="StackExchange\Redis\Exclude.cs" />
<Compile Include="StackExchange\Redis\ExportOptions.cs" />
<Compile Include="StackExchange\Redis\Format.cs" />
<Compile Include="StackExchange\Redis\IBatch.cs" />
<Compile Include="StackExchange\Redis\IMultiMessage.cs" />
<Compile Include="StackExchange\Redis\Order.cs" />
<Compile Include="StackExchange\Redis\RedisBatch.cs" />
<Compile Include="StackExchange\Redis\RedisCommand.cs" />
<Compile Include="StackExchange\Redis\RedisErrorEventArgs.cs" />
<Compile Include="StackExchange\Redis\HashSlotMovedEventArgs.cs" />
<Compile Include="StackExchange\Redis\ITransaction.cs" />
<Compile Include="StackExchange\Redis\IRedis.cs" />
<Compile Include="StackExchange\Redis\IRedisAsync.cs" />
<Compile Include="StackExchange\Redis\IDatabase.cs" />
<Compile Include="StackExchange\Redis\IDatabaseAsync.cs" />
<Compile Include="StackExchange\Redis\IServer.cs" />
<Compile Include="StackExchange\Redis\ISubscriber.cs" />
<Compile Include="StackExchange\Redis\MessageCompletable.cs" />
<Compile Include="StackExchange\Redis\RedisBase.cs" />
<Compile Include="StackExchange\Redis\CommandFlags.cs" />
<Compile Include="StackExchange\Redis\CommandMap.cs" />
<Compile Include="StackExchange\Redis\CompletionManager.cs" />
<Compile Include="StackExchange\Redis\ConnectionMultiplexer.cs" />
<Compile Include="StackExchange\Redis\CompletedDefaultTask.cs" />
<Compile Include="StackExchange\Redis\ICompletable.cs" />
<Compile Include="StackExchange\Redis\LoggingTextStream.cs" />
<Compile Include="StackExchange\Redis\PhysicalBridge.cs" />
<Compile Include="StackExchange\Redis\Message.cs" />
<Compile Include="StackExchange\Redis\MessageQueue.cs" />
<Compile Include="StackExchange\Redis\PhysicalConnection.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="StackExchange\Redis\RedisResult.cs" />
<Compile Include="StackExchange\Redis\RedisTransaction.cs" />
<Compile Include="StackExchange\Redis\RedisDatabase.cs" />
<Compile Include="StackExchange\Redis\RedisFeatures.cs" />
<Compile Include="StackExchange\Redis\RedisKey.cs" />
<Compile Include="StackExchange\Redis\RedisLiterals.cs" />
<Compile Include="StackExchange\Redis\RedisServer.cs" />
<Compile Include="StackExchange\Redis\RedisType.cs" />
<Compile Include="StackExchange\Redis\RedisValue.cs" />
<Compile Include="StackExchange\Redis\ReplicationChangeOptions.cs" />
<Compile Include="StackExchange\Redis\RawResult.cs" />
<Compile Include="StackExchange\Redis\ResultBox.cs" />
<Compile Include="StackExchange\Redis\ResultProcessor.cs" />
<Compile Include="StackExchange\Redis\RedisSubscriber.cs" />
<Compile Include="StackExchange\Redis\ResultType.cs" />
<Compile Include="StackExchange\Redis\ScriptParameterMapper.cs" />
<Compile Include="StackExchange\Redis\ServerCounters.cs" />
<Compile Include="StackExchange\Redis\ServerEndPoint.cs" />
<Compile Include="StackExchange\Redis\ServerSelectionStrategy.cs" />
<Compile Include="StackExchange\Redis\ServerType.cs" />
<Compile Include="StackExchange\Redis\SetOperation.cs" />
<Compile Include="StackExchange\Redis\SocketManager.cs" />
<Compile Include="StackExchange\Redis\SocketManager.NoPoll.cs">
<DependentUpon>SocketManager.cs</DependentUpon>
</Compile>
<Compile Include="StackExchange\Redis\SortedSetEntry.cs" />
<Compile Include="StackExchange\Redis\SortType.cs" />
<Compile Include="StackExchange\Redis\StringSplits.cs" />
<Compile Include="StackExchange\Redis\TaskSource.cs" />
<Compile Include="StackExchange\Redis\When.cs" />
<Compile Include="StackExchange\Redis\ShutdownMode.cs" />
<Compile Include="StackExchange\Redis\SaveType.cs" />
<Compile Include="StackExchange\Redis\KeyspaceIsolation\BatchWrapper.cs" />
<Compile Include="StackExchange\Redis\KeyspaceIsolation\DatabaseExtension.cs" />
<Compile Include="StackExchange\Redis\KeyspaceIsolation\DatabaseWrapper.cs" />
<Compile Include="StackExchange\Redis\KeyspaceIsolation\TransactionWrapper.cs" />
<Compile Include="StackExchange\Redis\KeyspaceIsolation\WrapperBase.cs" />
</ItemGroup>
<ItemGroup>
<Compile Include="StackExchange\Redis\SocketManager.Poll.cs">
<DependentUpon>SocketManager.cs</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<None Include="StackExchange.Redis.snk" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>
using System;
using System.Collections.Generic;
using System.Text;
namespace StackExchange.Redis
{
/// <summary>
/// Represents the commands mapped on a particular configuration
/// </summary>
public sealed class CommandMap
{
private static readonly CommandMap
@default = CreateImpl(null, null),
twemproxy = CreateImpl(null, exclusions: new HashSet<RedisCommand>
{
// see https://github.com/twitter/twemproxy/blob/master/notes/redis.md
RedisCommand.KEYS, RedisCommand.MIGRATE, RedisCommand.MOVE, RedisCommand.OBJECT, RedisCommand.RANDOMKEY,
RedisCommand.RENAME, RedisCommand.RENAMENX, RedisCommand.SORT, RedisCommand.SCAN,
RedisCommand.BITOP, RedisCommand.MSET, RedisCommand.MSETNX,
RedisCommand.HSCAN,
RedisCommand.BLPOP, RedisCommand.BRPOP, RedisCommand.BRPOPLPUSH, // yeah, me neither!
RedisCommand.SSCAN,
RedisCommand.ZSCAN,
RedisCommand.PSUBSCRIBE, RedisCommand.PUBLISH, RedisCommand.PUNSUBSCRIBE, RedisCommand.SUBSCRIBE, RedisCommand.UNSUBSCRIBE,
RedisCommand.DISCARD, RedisCommand.EXEC, RedisCommand.MULTI, RedisCommand.UNWATCH, RedisCommand.WATCH,
RedisCommand.SCRIPT,
RedisCommand.AUTH, RedisCommand.ECHO, RedisCommand.PING, RedisCommand.QUIT, RedisCommand.SELECT,
RedisCommand.BGREWRITEAOF, RedisCommand.BGSAVE, RedisCommand.CLIENT, RedisCommand.CLUSTER, RedisCommand.CONFIG, RedisCommand.DBSIZE,
RedisCommand.DEBUG, RedisCommand.FLUSHALL, RedisCommand.FLUSHDB, RedisCommand.INFO, RedisCommand.LASTSAVE, RedisCommand.MONITOR, RedisCommand.SAVE,
RedisCommand.SHUTDOWN, RedisCommand.SLAVEOF, RedisCommand.SLOWLOG, RedisCommand.SYNC, RedisCommand.TIME
}), ssdb = Create(new HashSet<string> {
// see http://www.ideawu.com/ssdb/docs/redis-to-ssdb.html
"ping",
"get", "set", "del", "incr", "incrby", "mget", "mset", "keys", "getset", "setnx",
"hget", "hset", "hdel", "hincrby", "hkeys", "hvals", "hmget", "hmset", "hlen",
"zscore", "zadd", "zrem", "zrange", "zrangebyscore", "zincrby", "zdecrby", "zcard",
"llen", "lpush", "rpush", "lpop", "rpop", "lrange", "lindex"
}, true),
sentinel = Create(new HashSet<string> {
// see http://redis.io/topics/sentinel
"ping", "info", "sentinel", "subscribe", "psubscribe", "unsubscribe", "punsubscribe" }, true);
private readonly byte[][] map;
internal CommandMap(byte[][] map)
{
this.map = map;
}
/// <summary>
/// The default commands specified by redis
/// </summary>
public static CommandMap Default { get { return @default; } }
/// <summary>
/// The commands available to <a href="twemproxy">https://github.com/twitter/twemproxy</a>
/// </summary>
/// <remarks>https://github.com/twitter/twemproxy/blob/master/notes/redis.md</remarks>
public static CommandMap Twemproxy { get { return twemproxy; } }
/// <summary>
/// The commands available to <a href="ssdb">http://www.ideawu.com/ssdb/</a>
/// </summary>
/// <remarks>http://www.ideawu.com/ssdb/docs/redis-to-ssdb.html</remarks>
public static CommandMap SSDB { get { return ssdb; } }
/// <summary>
/// The commands available to <a href="Sentinel">http://redis.io/topics/sentinel</a>
/// </summary>
/// <remarks>http://redis.io/topics/sentinel</remarks>
public static CommandMap Sentinel { get { return sentinel; } }
/// <summary>
/// Create a new CommandMap, customizing some commands
/// </summary>
public static CommandMap Create(Dictionary<string, string> overrides)
{
if (overrides == null || overrides.Count == 0) return Default;
if (ReferenceEquals(overrides.Comparer, StringComparer.OrdinalIgnoreCase))
{
// that's ok; we're happy with ordinal/invariant case-insensitive
// (but not culture-specific insensitive; completely untested)
}
else
{
// need case insensitive
overrides = new Dictionary<string, string>(overrides, StringComparer.OrdinalIgnoreCase);
}
return CreateImpl(overrides, null);
}
/// <summary>
/// Creates a CommandMap by specifying which commands are available or unavailable
/// </summary>
public static CommandMap Create(HashSet<string> commands, bool available = true)
{
if (available)
{
var dictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
// nix everything
foreach (RedisCommand command in Enum.GetValues(typeof(RedisCommand)))
{
dictionary[command.ToString()] = null;
}
if (commands != null)
{
// then include (by removal) the things that are available
foreach (string command in commands)
{
dictionary.Remove(command);
}
}
return CreateImpl(dictionary, null);
}
else
{
HashSet<RedisCommand> exclusions = null;
if (commands != null)
{
// nix the things that are specified
foreach (var command in commands)
{
RedisCommand parsed;
if (Enum.TryParse(command, true, out parsed))
{
(exclusions ?? (exclusions = new HashSet<RedisCommand>())).Add(parsed);
}
}
}
if (exclusions == null || exclusions.Count == 0) return Default;
return CreateImpl(null, exclusions);
}
}
/// <summary>
/// See Object.ToString()
/// </summary>
public override string ToString()
{
var sb = new StringBuilder();
AppendDeltas(sb);
return sb.ToString();
}
internal void AppendDeltas(StringBuilder sb)
{
for (int i = 0; i < map.Length; i++)
{
var key = ((RedisCommand)i).ToString();
var value = map[i] == null ? "" : Encoding.UTF8.GetString(map[i]);
if (key != value)
{
if (sb.Length != 0) sb.Append(',');
sb.Append('$').Append(key).Append('=').Append(value);
}
}
}
internal void AssertAvailable(RedisCommand command)
{
if (map[(int)command] == null) throw ExceptionFactory.CommandDisabled(false, command, null, null);
}
internal byte[] GetBytes(RedisCommand command)
{
return map[(int)command];
}
internal bool IsAvailable(RedisCommand command)
{
return map[(int)command] != null;
}
private static CommandMap CreateImpl(Dictionary<string, string> caseInsensitiveOverrides, HashSet<RedisCommand> exclusions)
{
var commands = (RedisCommand[])Enum.GetValues(typeof(RedisCommand));
byte[][] map = new byte[commands.Length][];
bool haveDelta = false;
for (int i = 0; i < commands.Length; i++)
{
int idx = (int)commands[i];
string name = commands[i].ToString(), value = name;
if (exclusions != null && exclusions.Contains(commands[i]))
{
map[idx] = null;
}
else
{
if (caseInsensitiveOverrides != null)
{
string tmp;
if (caseInsensitiveOverrides.TryGetValue(name, out tmp))
{
value = tmp;
}
}
if (value != name) haveDelta = true;
haveDelta = true;
byte[] val = string.IsNullOrWhiteSpace(value) ? null : Encoding.UTF8.GetBytes(value);
map[idx] = val;
}
}
if (!haveDelta && @default != null) return @default;
return new CommandMap(map);
}
}
}
using System;
using System.Collections.Generic;
using System.Text;
namespace StackExchange.Redis
{
/// <summary>
/// Represents the commands mapped on a particular configuration
/// </summary>
public sealed class CommandMap
{
private static readonly CommandMap
@default = CreateImpl(null, null),
twemproxy = CreateImpl(null, exclusions: new HashSet<RedisCommand>
{
// see https://github.com/twitter/twemproxy/blob/master/notes/redis.md
RedisCommand.KEYS, RedisCommand.MIGRATE, RedisCommand.MOVE, RedisCommand.OBJECT, RedisCommand.RANDOMKEY,
RedisCommand.RENAME, RedisCommand.RENAMENX, RedisCommand.SORT, RedisCommand.SCAN,
RedisCommand.BITOP, RedisCommand.MSET, RedisCommand.MSETNX,
RedisCommand.HSCAN,
RedisCommand.BLPOP, RedisCommand.BRPOP, RedisCommand.BRPOPLPUSH, // yeah, me neither!
RedisCommand.SSCAN,
RedisCommand.ZSCAN,
RedisCommand.PSUBSCRIBE, RedisCommand.PUBLISH, RedisCommand.PUNSUBSCRIBE, RedisCommand.SUBSCRIBE, RedisCommand.UNSUBSCRIBE,
RedisCommand.DISCARD, RedisCommand.EXEC, RedisCommand.MULTI, RedisCommand.UNWATCH, RedisCommand.WATCH,
RedisCommand.SCRIPT,
RedisCommand.AUTH, RedisCommand.ECHO, RedisCommand.PING, RedisCommand.QUIT, RedisCommand.SELECT,
RedisCommand.BGREWRITEAOF, RedisCommand.BGSAVE, RedisCommand.CLIENT, RedisCommand.CLUSTER, RedisCommand.CONFIG, RedisCommand.DBSIZE,
RedisCommand.DEBUG, RedisCommand.FLUSHALL, RedisCommand.FLUSHDB, RedisCommand.INFO, RedisCommand.LASTSAVE, RedisCommand.MONITOR, RedisCommand.SAVE,
RedisCommand.SHUTDOWN, RedisCommand.SLAVEOF, RedisCommand.SLOWLOG, RedisCommand.SYNC, RedisCommand.TIME
}), ssdb = Create(new HashSet<string> {
// see http://www.ideawu.com/ssdb/docs/redis-to-ssdb.html
"ping",
"get", "set", "del", "incr", "incrby", "mget", "mset", "keys", "getset", "setnx",
"hget", "hset", "hdel", "hincrby", "hkeys", "hvals", "hmget", "hmset", "hlen",
"zscore", "zadd", "zrem", "zrange", "zrangebyscore", "zincrby", "zdecrby", "zcard",
"llen", "lpush", "rpush", "lpop", "rpop", "lrange", "lindex"
}, true),
sentinel = Create(new HashSet<string> {
// see http://redis.io/topics/sentinel
"ping", "info", "sentinel", "subscribe", "psubscribe", "unsubscribe", "punsubscribe" }, true);
private readonly byte[][] map;
internal CommandMap(byte[][] map)
{
this.map = map;
}
/// <summary>
/// The default commands specified by redis
/// </summary>
public static CommandMap Default { get { return @default; } }
/// <summary>
/// The commands available to <a href="twemproxy">https://github.com/twitter/twemproxy</a>
/// </summary>
/// <remarks>https://github.com/twitter/twemproxy/blob/master/notes/redis.md</remarks>
public static CommandMap Twemproxy { get { return twemproxy; } }
/// <summary>
/// The commands available to <a href="ssdb">http://www.ideawu.com/ssdb/</a>
/// </summary>
/// <remarks>http://www.ideawu.com/ssdb/docs/redis-to-ssdb.html</remarks>
public static CommandMap SSDB { get { return ssdb; } }
/// <summary>
/// The commands available to <a href="Sentinel">http://redis.io/topics/sentinel</a>
/// </summary>
/// <remarks>http://redis.io/topics/sentinel</remarks>
public static CommandMap Sentinel { get { return sentinel; } }
/// <summary>
/// Create a new CommandMap, customizing some commands
/// </summary>
public static CommandMap Create(Dictionary<string, string> overrides)
{
if (overrides == null || overrides.Count == 0) return Default;
if (ReferenceEquals(overrides.Comparer, StringComparer.OrdinalIgnoreCase))
{
// that's ok; we're happy with ordinal/invariant case-insensitive
// (but not culture-specific insensitive; completely untested)
}
else
{
// need case insensitive
overrides = new Dictionary<string, string>(overrides, StringComparer.OrdinalIgnoreCase);
}
return CreateImpl(overrides, null);
}
/// <summary>
/// Creates a CommandMap by specifying which commands are available or unavailable
/// </summary>
public static CommandMap Create(HashSet<string> commands, bool available = true)
{
if (available)
{
var dictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
// nix everything
foreach (RedisCommand command in Enum.GetValues(typeof(RedisCommand)))
{
dictionary[command.ToString()] = null;
}
if (commands != null)
{
// then include (by removal) the things that are available
foreach (string command in commands)
{
dictionary.Remove(command);
}
}
return CreateImpl(dictionary, null);
}
else
{
HashSet<RedisCommand> exclusions = null;
if (commands != null)
{
// nix the things that are specified
foreach (var command in commands)
{
RedisCommand parsed;
if (Enum.TryParse(command, true, out parsed))
{
(exclusions ?? (exclusions = new HashSet<RedisCommand>())).Add(parsed);
}
}
}
if (exclusions == null || exclusions.Count == 0) return Default;
return CreateImpl(null, exclusions);
}
}
/// <summary>
/// See Object.ToString()
/// </summary>
public override string ToString()
{
var sb = new StringBuilder();
AppendDeltas(sb);
return sb.ToString();
}
internal void AppendDeltas(StringBuilder sb)
{
for (int i = 0; i < map.Length; i++)
{
var key = ((RedisCommand)i).ToString();
var value = map[i] == null ? "" : Encoding.UTF8.GetString(map[i]);
if (key != value)
{
if (sb.Length != 0) sb.Append(',');
sb.Append('$').Append(key).Append('=').Append(value);
}
}
}
internal void AssertAvailable(RedisCommand command)
{
if (map[(int)command] == null) throw ExceptionFactory.CommandDisabled(false, command, null, null);
}
internal byte[] GetBytes(RedisCommand command)
{
return map[(int)command];
}
internal bool IsAvailable(RedisCommand command)
{
return map[(int)command] != null;
}
private static CommandMap CreateImpl(Dictionary<string, string> caseInsensitiveOverrides, HashSet<RedisCommand> exclusions)
{
var commands = (RedisCommand[])Enum.GetValues(typeof(RedisCommand));
byte[][] map = new byte[commands.Length][];
bool haveDelta = false;
for (int i = 0; i < commands.Length; i++)
{
int idx = (int)commands[i];
string name = commands[i].ToString(), value = name;
if (exclusions != null && exclusions.Contains(commands[i]))
{
map[idx] = null;
}
else
{
if (caseInsensitiveOverrides != null)
{
string tmp;
if (caseInsensitiveOverrides.TryGetValue(name, out tmp))
{
value = tmp;
}
}
if (value != name) haveDelta = true;
haveDelta = true;
byte[] val = string.IsNullOrWhiteSpace(value) ? null : Encoding.UTF8.GetBytes(value);
map[idx] = val;
}
}
if (!haveDelta && @default != null) return @default;
return new CommandMap(map);
}
}
}
using System;
using System.Collections.Generic;
namespace StackExchange.Redis
{
/// <summary>
/// Utility methods
/// </summary>
public static class ExtensionMethods
{
/// <summary>
/// Create a dictionary from an array of HashEntry values
/// </summary>
public static Dictionary<string,string> ToStringDictionary(this HashEntry[] hash)
{
if (hash == null) return null;
var result = new Dictionary<string, string>(hash.Length, StringComparer.Ordinal);
for(int i = 0; i < hash.Length; i++)
{
result.Add(hash[i].name, hash[i].value);
}
return result;
}
/// <summary>
/// Create a dictionary from an array of HashEntry values
/// </summary>
public static Dictionary<RedisValue, RedisValue> ToDictionary(this HashEntry[] hash)
{
if (hash == null) return null;
var result = new Dictionary<RedisValue, RedisValue>(hash.Length);
for (int i = 0; i < hash.Length; i++)
{
result.Add(hash[i].name, hash[i].value);
}
return result;
}
/// <summary>
/// Create a dictionary from an array of SortedSetEntry values
/// </summary>
public static Dictionary<string, double> ToStringDictionary(this SortedSetEntry[] sortedSet)
{
if (sortedSet == null) return null;
var result = new Dictionary<string, double>(sortedSet.Length, StringComparer.Ordinal);
for (int i = 0; i < sortedSet.Length; i++)
{
result.Add(sortedSet[i].element, sortedSet[i].score);
}
return result;
}
/// <summary>
/// Create a dictionary from an array of SortedSetEntry values
/// </summary>
public static Dictionary<RedisValue, double> ToDictionary(this SortedSetEntry[] sortedSet)
{
if (sortedSet == null) return null;
var result = new Dictionary<RedisValue, double>(sortedSet.Length);
for (int i = 0; i < sortedSet.Length; i++)
{
result.Add(sortedSet[i].element, sortedSet[i].score);
}
return result;
}
/// <summary>
/// Create a dictionary from an array of key/value pairs
/// </summary>
public static Dictionary<string, string> ToStringDictionary(this KeyValuePair<RedisKey, RedisValue>[] pairs)
{
if (pairs == null) return null;
var result = new Dictionary<string, string>(pairs.Length, StringComparer.Ordinal);
for (int i = 0; i < pairs.Length; i++)
{
result.Add(pairs[i].Key, pairs[i].Value);
}
return result;
}
/// <summary>
/// Create a dictionary from an array of key/value pairs
/// </summary>
public static Dictionary<RedisKey, RedisValue> ToDictionary(this KeyValuePair<RedisKey, RedisValue>[] pairs)
{
if (pairs == null) return null;
var result = new Dictionary<RedisKey, RedisValue>(pairs.Length);
for (int i = 0; i < pairs.Length; i++)
{
result.Add(pairs[i].Key, pairs[i].Value);
}
return result;
}
/// <summary>
/// Create a dictionary from an array of string pairs
/// </summary>
public static Dictionary<string, string> ToDictionary(this KeyValuePair<string, string>[] pairs)
{
if (pairs == null) return null;
var result = new Dictionary<string, string>(pairs.Length, StringComparer.Ordinal);
for (int i = 0; i < pairs.Length; i++)
{
result.Add(pairs[i].Key, pairs[i].Value);
}
return result;
}
static readonly string[] nix = new string[0];
/// <summary>
/// Create an array of strings from an array of values
/// </summary>
public static string[] ToStringArray(this RedisValue[] values)
{
if (values == null) return null;
if (values.Length == 0) return nix;
return ConvertHelper.ConvertAll(values, x => (string)x);
}
}
}
using System;
using System.Collections.Generic;
namespace StackExchange.Redis
{
/// <summary>
/// Utility methods
/// </summary>
public static class ExtensionMethods
{
/// <summary>
/// Create a dictionary from an array of HashEntry values
/// </summary>
public static Dictionary<string,string> ToStringDictionary(this HashEntry[] hash)
{
if (hash == null) return null;
var result = new Dictionary<string, string>(hash.Length, StringComparer.Ordinal);
for(int i = 0; i < hash.Length; i++)
{
result.Add(hash[i].name, hash[i].value);
}
return result;
}
/// <summary>
/// Create a dictionary from an array of HashEntry values
/// </summary>
public static Dictionary<RedisValue, RedisValue> ToDictionary(this HashEntry[] hash)
{
if (hash == null) return null;
var result = new Dictionary<RedisValue, RedisValue>(hash.Length);
for (int i = 0; i < hash.Length; i++)
{
result.Add(hash[i].name, hash[i].value);
}
return result;
}
/// <summary>
/// Create a dictionary from an array of SortedSetEntry values
/// </summary>
public static Dictionary<string, double> ToStringDictionary(this SortedSetEntry[] sortedSet)
{
if (sortedSet == null) return null;
var result = new Dictionary<string, double>(sortedSet.Length, StringComparer.Ordinal);
for (int i = 0; i < sortedSet.Length; i++)
{
result.Add(sortedSet[i].element, sortedSet[i].score);
}
return result;
}
/// <summary>
/// Create a dictionary from an array of SortedSetEntry values
/// </summary>
public static Dictionary<RedisValue, double> ToDictionary(this SortedSetEntry[] sortedSet)
{
if (sortedSet == null) return null;
var result = new Dictionary<RedisValue, double>(sortedSet.Length);
for (int i = 0; i < sortedSet.Length; i++)
{
result.Add(sortedSet[i].element, sortedSet[i].score);
}
return result;
}
/// <summary>
/// Create a dictionary from an array of key/value pairs
/// </summary>
public static Dictionary<string, string> ToStringDictionary(this KeyValuePair<RedisKey, RedisValue>[] pairs)
{
if (pairs == null) return null;
var result = new Dictionary<string, string>(pairs.Length, StringComparer.Ordinal);
for (int i = 0; i < pairs.Length; i++)
{
result.Add(pairs[i].Key, pairs[i].Value);
}
return result;
}
/// <summary>
/// Create a dictionary from an array of key/value pairs
/// </summary>
public static Dictionary<RedisKey, RedisValue> ToDictionary(this KeyValuePair<RedisKey, RedisValue>[] pairs)
{
if (pairs == null) return null;
var result = new Dictionary<RedisKey, RedisValue>(pairs.Length);
for (int i = 0; i < pairs.Length; i++)
{
result.Add(pairs[i].Key, pairs[i].Value);
}
return result;
}
/// <summary>
/// Create a dictionary from an array of string pairs
/// </summary>
public static Dictionary<string, string> ToDictionary(this KeyValuePair<string, string>[] pairs)
{
if (pairs == null) return null;
var result = new Dictionary<string, string>(pairs.Length, StringComparer.Ordinal);
for (int i = 0; i < pairs.Length; i++)
{
result.Add(pairs[i].Key, pairs[i].Value);
}
return result;
}
static readonly string[] nix = new string[0];
/// <summary>
/// Create an array of strings from an array of values
/// </summary>
public static string[] ToStringArray(this RedisValue[] values)
{
if (values == null) return null;
if (values.Length == 0) return nix;
return ConvertHelper.ConvertAll(values, x => (string)x);
}
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
namespace StackExchange.Redis
{
/// <summary>
/// Describes a hash-field (a name/value pair)
/// </summary>
public struct HashEntry : IEquatable<HashEntry>
{
internal readonly RedisValue name, value;
/// <summary>
/// Initializes a HashEntry value
/// </summary>
public HashEntry(RedisValue name, RedisValue value)
{
this.name = name;
this.value = value;
}
/// <summary>
/// The name of the hash field
/// </summary>
public RedisValue Name { get { return name; } }
/// <summary>
/// The value of the hash field
/// </summary>
public RedisValue Value{ get { return value; } }
/// <summary>
/// The name of the hash field
/// </summary>
#if !DNXCORE50
[Browsable(false)]
#endif
[EditorBrowsable(EditorBrowsableState.Never), Obsolete("Please use Name", false)]
public RedisValue Key { get { return name; } }
/// <summary>
/// Converts to a key/value pair
/// </summary>
public static implicit operator KeyValuePair<RedisValue, RedisValue>(HashEntry value)
{
return new KeyValuePair<RedisValue, RedisValue>(value.name, value.value);
}
/// <summary>
/// Converts from a key/value pair
/// </summary>
public static implicit operator HashEntry(KeyValuePair<RedisValue, RedisValue> value)
{
return new HashEntry(value.Key, value.Value);
}
/// <summary>
/// See Object.ToString()
/// </summary>
public override string ToString()
{
return name + ": " + value;
}
/// <summary>
/// See Object.GetHashCode()
/// </summary>
public override int GetHashCode()
{
return name.GetHashCode() ^ value.GetHashCode();
}
/// <summary>
/// Compares two values for equality
/// </summary>
public override bool Equals(object obj)
{
return obj is HashEntry && Equals((HashEntry)obj);
}
/// <summary>
/// Compares two values for equality
/// </summary>
public bool Equals(HashEntry value)
{
return this.name == value.name && this.value == value.value;
}
/// <summary>
/// Compares two values for equality
/// </summary>
public static bool operator ==(HashEntry x, HashEntry y)
{
return x.name == y.name && x.value == y.value;
}
/// <summary>
/// Compares two values for non-equality
/// </summary>
public static bool operator !=(HashEntry x, HashEntry y)
{
return x.name != y.name || x.value != y.value;
}
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
namespace StackExchange.Redis
{
/// <summary>
/// Describes a hash-field (a name/value pair)
/// </summary>
public struct HashEntry : IEquatable<HashEntry>
{
internal readonly RedisValue name, value;
/// <summary>
/// Initializes a HashEntry value
/// </summary>
public HashEntry(RedisValue name, RedisValue value)
{
this.name = name;
this.value = value;
}
/// <summary>
/// The name of the hash field
/// </summary>
public RedisValue Name { get { return name; } }
/// <summary>
/// The value of the hash field
/// </summary>
public RedisValue Value{ get { return value; } }
/// <summary>
/// The name of the hash field
/// </summary>
#if !DNXCORE50
[Browsable(false)]
#endif
[EditorBrowsable(EditorBrowsableState.Never), Obsolete("Please use Name", false)]
public RedisValue Key { get { return name; } }
/// <summary>
/// Converts to a key/value pair
/// </summary>
public static implicit operator KeyValuePair<RedisValue, RedisValue>(HashEntry value)
{
return new KeyValuePair<RedisValue, RedisValue>(value.name, value.value);
}
/// <summary>
/// Converts from a key/value pair
/// </summary>
public static implicit operator HashEntry(KeyValuePair<RedisValue, RedisValue> value)
{
return new HashEntry(value.Key, value.Value);
}
/// <summary>
/// See Object.ToString()
/// </summary>
public override string ToString()
{
return name + ": " + value;
}
/// <summary>
/// See Object.GetHashCode()
/// </summary>
public override int GetHashCode()
{
return name.GetHashCode() ^ value.GetHashCode();
}
/// <summary>
/// Compares two values for equality
/// </summary>
public override bool Equals(object obj)
{
return obj is HashEntry && Equals((HashEntry)obj);
}
/// <summary>
/// Compares two values for equality
/// </summary>
public bool Equals(HashEntry value)
{
return this.name == value.name && this.value == value.value;
}
/// <summary>
/// Compares two values for equality
/// </summary>
public static bool operator ==(HashEntry x, HashEntry y)
{
return x.name == y.name && x.value == y.value;
}
/// <summary>
/// Compares two values for non-equality
/// </summary>
public static bool operator !=(HashEntry x, HashEntry y)
{
return x.name != y.name || x.value != y.value;
}
}
}
using System;
using System.Linq;
namespace StackExchange.Redis
{
/// <summary>
/// Represents a general-purpose result from redis, that may be cast into various anticipated types
/// </summary>
public abstract class RedisResult
{
// internally, this is very similar to RawResult, except it is designed to be usable
// outside of the IO-processing pipeline: the buffers are standalone, etc
internal static RedisResult TryCreate(PhysicalConnection connection, RawResult result)
{
try
{
switch (result.Type)
{
case ResultType.Integer:
case ResultType.SimpleString:
case ResultType.BulkString:
return new SingleRedisResult(result.AsRedisValue());
case ResultType.MultiBulk:
var items = result.GetItems();
var arr = new RedisResult[items.Length];
for (int i = 0; i < arr.Length; i++)
{
var next = TryCreate(connection, items[i]);
if (next == null) return null; // means we didn't understand
arr[i] = next;
}
return new ArrayRedisResult(arr);
case ResultType.Error:
return new ErrorRedisResult(result.GetString());
default:
return null;
}
} catch(Exception ex)
{
if(connection != null) connection.OnInternalError(ex);
return null; // will be logged as a protocol fail by the processor
}
}
/// <summary>
/// Indicates whether this result was a null result
/// </summary>
public abstract bool IsNull { get; }
/// <summary>
/// Interprets the result as a String
/// </summary>
public static explicit operator string (RedisResult result) { return result.AsString(); }
/// <summary>
/// Interprets the result as a Byte[]
/// </summary>
public static explicit operator byte[] (RedisResult result) { return result.AsByteArray(); }
/// <summary>
/// Interprets the result as a Double
/// </summary>
public static explicit operator double (RedisResult result) { return result.AsDouble(); }
/// <summary>
/// Interprets the result as an Int64
/// </summary>
public static explicit operator long (RedisResult result) { return result.AsInt64(); }
/// <summary>
/// Interprets the result as an Int32
/// </summary>
public static explicit operator int (RedisResult result) { return result.AsInt32(); }
/// <summary>
/// Interprets the result as a Boolean
/// </summary>
public static explicit operator bool (RedisResult result) { return result.AsBoolean(); }
/// <summary>
/// Interprets the result as a RedisValue
/// </summary>
public static explicit operator RedisValue (RedisResult result) { return result.AsRedisValue(); }
/// <summary>
/// Interprets the result as a RedisKey
/// </summary>
public static explicit operator RedisKey (RedisResult result) { return result.AsRedisKey(); }
/// <summary>
/// Interprets the result as a Nullable Double
/// </summary>
public static explicit operator double? (RedisResult result) { return result.AsNullableDouble(); }
/// <summary>
/// Interprets the result as a Nullable Int64
/// </summary>
public static explicit operator long? (RedisResult result) { return result.AsNullableInt64(); }
/// <summary>
/// Interprets the result as a Nullable Int32
/// </summary>
public static explicit operator int? (RedisResult result) { return result.AsNullableInt32(); }
/// <summary>
/// Interprets the result as a Nullable Boolean
/// </summary>
public static explicit operator bool? (RedisResult result) { return result.AsNullableBoolean(); }
/// <summary>
/// Interprets the result as an array of String
/// </summary>
public static explicit operator string[] (RedisResult result) { return result.AsStringArray(); }
/// <summary>
/// Interprets the result as an array of Byte[]
/// </summary>
public static explicit operator byte[][] (RedisResult result) { return result.AsByteArrayArray(); }
/// <summary>
/// Interprets the result as an array of Double
/// </summary>
public static explicit operator double[] (RedisResult result) { return result.AsDoubleArray(); }
/// <summary>
/// Interprets the result as an array of Int64
/// </summary>
public static explicit operator long[] (RedisResult result) { return result.AsInt64Array(); }
/// <summary>
/// Interprets the result as an array of Int32
/// </summary>
public static explicit operator int[] (RedisResult result) { return result.AsInt32Array(); }
/// <summary>
/// Interprets the result as an array of Boolean
/// </summary>
public static explicit operator bool[] (RedisResult result) { return result.AsBooleanArray(); }
/// <summary>
/// Interprets the result as an array of RedisValue
/// </summary>
public static explicit operator RedisValue[] (RedisResult result) { return result.AsRedisValueArray(); }
/// <summary>
/// Interprets the result as an array of RedisKey
/// </summary>
public static explicit operator RedisKey[] (RedisResult result) { return result.AsRedisKeyArray(); }
/// <summary>
/// Interprets the result as an array of RedisResult
/// </summary>
public static explicit operator RedisResult[] (RedisResult result) { return result.AsRedisResultArray(); }
internal abstract bool AsBoolean();
internal abstract bool[] AsBooleanArray();
internal abstract byte[] AsByteArray();
internal abstract byte[][] AsByteArrayArray();
internal abstract double AsDouble();
internal abstract double[] AsDoubleArray();
internal abstract int AsInt32();
internal abstract int[] AsInt32Array();
internal abstract long AsInt64();
internal abstract long[] AsInt64Array();
internal abstract bool? AsNullableBoolean();
internal abstract double? AsNullableDouble();
internal abstract int? AsNullableInt32();
internal abstract long? AsNullableInt64();
internal abstract RedisKey AsRedisKey();
internal abstract RedisKey[] AsRedisKeyArray();
internal abstract RedisResult[] AsRedisResultArray();
internal abstract RedisValue AsRedisValue();
internal abstract RedisValue[] AsRedisValueArray();
internal abstract string AsString();
internal abstract string[] AsStringArray();
private sealed class ArrayRedisResult : RedisResult
{
public override bool IsNull
{
get { return value == null; }
}
private readonly RedisResult[] value;
public ArrayRedisResult(RedisResult[] value)
{
if (value == null) throw new ArgumentNullException("value");
this.value = value;
}
public override string ToString()
{
return value.Length + " element(s)";
}
internal override bool AsBoolean()
{
if (value.Length == 1) return value[0].AsBoolean();
throw new InvalidCastException();
}
internal override bool[] AsBooleanArray() { return ConvertHelper.ConvertAll(value, x => x.AsBoolean()); }
internal override byte[] AsByteArray()
{
if (value.Length == 1) return value[0].AsByteArray();
throw new InvalidCastException();
}
internal override byte[][] AsByteArrayArray() { return ConvertHelper.ConvertAll(value, x => x.AsByteArray()); }
internal override double AsDouble()
{
if (value.Length == 1) return value[0].AsDouble();
throw new InvalidCastException();
}
internal override double[] AsDoubleArray() { return ConvertHelper.ConvertAll(value, x => x.AsDouble()); }
internal override int AsInt32()
{
if (value.Length == 1) return value[0].AsInt32();
throw new InvalidCastException();
}
internal override int[] AsInt32Array() { return ConvertHelper.ConvertAll(value, x => x.AsInt32()); }
internal override long AsInt64()
{
if (value.Length == 1) return value[0].AsInt64();
throw new InvalidCastException();
}
internal override long[] AsInt64Array() { return ConvertHelper.ConvertAll(value, x => x.AsInt64()); }
internal override bool? AsNullableBoolean()
{
if (value.Length == 1) return value[0].AsNullableBoolean();
throw new InvalidCastException();
}
internal override double? AsNullableDouble()
{
if (value.Length == 1) return value[0].AsNullableDouble();
throw new InvalidCastException();
}
internal override int? AsNullableInt32()
{
if (value.Length == 1) return value[0].AsNullableInt32();
throw new InvalidCastException();
}
internal override long? AsNullableInt64()
{
if (value.Length == 1) return value[0].AsNullableInt64();
throw new InvalidCastException();
}
internal override RedisKey AsRedisKey()
{
if (value.Length == 1) return value[0].AsRedisKey();
throw new InvalidCastException();
}
internal override RedisKey[] AsRedisKeyArray() { return ConvertHelper.ConvertAll(value, x => x.AsRedisKey()); }
internal override RedisResult[] AsRedisResultArray() { return value; }
internal override RedisValue AsRedisValue()
{
if (value.Length == 1) return value[0].AsRedisValue();
throw new InvalidCastException();
}
internal override RedisValue[] AsRedisValueArray() { return ConvertHelper.ConvertAll(value, x => x.AsRedisValue()); }
internal override string AsString()
{
if (value.Length == 1) return value[0].AsString();
throw new InvalidCastException();
}
internal override string[] AsStringArray() { return ConvertHelper.ConvertAll(value, x => x.AsString()); }
}
private sealed class ErrorRedisResult : RedisResult
{
private readonly string value;
public ErrorRedisResult(string value)
{
if (value == null) throw new ArgumentNullException("value");
this.value = value;
}
public override bool IsNull
{
get { return value == null; }
}
public override string ToString() { return value; }
internal override bool AsBoolean() { throw new RedisServerException(value); }
internal override bool[] AsBooleanArray() { throw new RedisServerException(value); }
internal override byte[] AsByteArray() { throw new RedisServerException(value); }
internal override byte[][] AsByteArrayArray() { throw new RedisServerException(value); }
internal override double AsDouble() { throw new RedisServerException(value); }
internal override double[] AsDoubleArray() { throw new RedisServerException(value); }
internal override int AsInt32() { throw new RedisServerException(value); }
internal override int[] AsInt32Array() { throw new RedisServerException(value); }
internal override long AsInt64() { throw new RedisServerException(value); }
internal override long[] AsInt64Array() { throw new RedisServerException(value); }
internal override bool? AsNullableBoolean() { throw new RedisServerException(value); }
internal override double? AsNullableDouble() { throw new RedisServerException(value); }
internal override int? AsNullableInt32() { throw new RedisServerException(value); }
internal override long? AsNullableInt64() { throw new RedisServerException(value); }
internal override RedisKey AsRedisKey() { throw new RedisServerException(value); }
internal override RedisKey[] AsRedisKeyArray() { throw new RedisServerException(value); }
internal override RedisResult[] AsRedisResultArray() { throw new RedisServerException(value); }
internal override RedisValue AsRedisValue() { throw new RedisServerException(value); }
internal override RedisValue[] AsRedisValueArray() { throw new RedisServerException(value); }
internal override string AsString() { throw new RedisServerException(value); }
internal override string[] AsStringArray() { throw new RedisServerException(value); }
}
private sealed class SingleRedisResult : RedisResult
{
private readonly RedisValue value;
public SingleRedisResult(RedisValue value)
{
this.value = value;
}
public override bool IsNull
{
get { return value.IsNull; }
}
public override string ToString() { return value.ToString(); }
internal override bool AsBoolean() { return (bool)value; }
internal override bool[] AsBooleanArray() { return new[] { AsBoolean() }; }
internal override byte[] AsByteArray() { return (byte[])value; }
internal override byte[][] AsByteArrayArray() { return new[] { AsByteArray() }; }
internal override double AsDouble() { return (double)value; }
internal override double[] AsDoubleArray() { return new[] { AsDouble() }; }
internal override int AsInt32() { return (int)value; }
internal override int[] AsInt32Array() { return new[] { AsInt32() }; }
internal override long AsInt64() { return (long)value; }
internal override long[] AsInt64Array() { return new[] { AsInt64() }; }
internal override bool? AsNullableBoolean() { return (bool?)value; }
internal override double? AsNullableDouble() { return (double?)value; }
internal override int? AsNullableInt32() { return (int?)value; }
internal override long? AsNullableInt64() { return (long?)value; }
internal override RedisKey AsRedisKey() { return (byte[])value; }
internal override RedisKey[] AsRedisKeyArray() { return new[] { AsRedisKey() }; }
internal override RedisResult[] AsRedisResultArray() { throw new InvalidCastException(); }
internal override RedisValue AsRedisValue() { return value; }
internal override RedisValue[] AsRedisValueArray() { return new[] { AsRedisValue() }; }
internal override string AsString() { return (string)value; }
internal override string[] AsStringArray() { return new[] { AsString() }; }
}
}
}
using System;
namespace StackExchange.Redis
{
/// <summary>
/// Represents a general-purpose result from redis, that may be cast into various anticipated types
/// </summary>
public abstract class RedisResult
{
// internally, this is very similar to RawResult, except it is designed to be usable
// outside of the IO-processing pipeline: the buffers are standalone, etc
internal static RedisResult TryCreate(PhysicalConnection connection, RawResult result)
{
try
{
switch (result.Type)
{
case ResultType.Integer:
case ResultType.SimpleString:
case ResultType.BulkString:
return new SingleRedisResult(result.AsRedisValue());
case ResultType.MultiBulk:
var items = result.GetItems();
var arr = new RedisResult[items.Length];
for (int i = 0; i < arr.Length; i++)
{
var next = TryCreate(connection, items[i]);
if (next == null) return null; // means we didn't understand
arr[i] = next;
}
return new ArrayRedisResult(arr);
case ResultType.Error:
return new ErrorRedisResult(result.GetString());
default:
return null;
}
} catch(Exception ex)
{
if(connection != null) connection.OnInternalError(ex);
return null; // will be logged as a protocol fail by the processor
}
}
/// <summary>
/// Indicates whether this result was a null result
/// </summary>
public abstract bool IsNull { get; }
/// <summary>
/// Interprets the result as a String
/// </summary>
public static explicit operator string (RedisResult result) { return result.AsString(); }
/// <summary>
/// Interprets the result as a Byte[]
/// </summary>
public static explicit operator byte[] (RedisResult result) { return result.AsByteArray(); }
/// <summary>
/// Interprets the result as a Double
/// </summary>
public static explicit operator double (RedisResult result) { return result.AsDouble(); }
/// <summary>
/// Interprets the result as an Int64
/// </summary>
public static explicit operator long (RedisResult result) { return result.AsInt64(); }
/// <summary>
/// Interprets the result as an Int32
/// </summary>
public static explicit operator int (RedisResult result) { return result.AsInt32(); }
/// <summary>
/// Interprets the result as a Boolean
/// </summary>
public static explicit operator bool (RedisResult result) { return result.AsBoolean(); }
/// <summary>
/// Interprets the result as a RedisValue
/// </summary>
public static explicit operator RedisValue (RedisResult result) { return result.AsRedisValue(); }
/// <summary>
/// Interprets the result as a RedisKey
/// </summary>
public static explicit operator RedisKey (RedisResult result) { return result.AsRedisKey(); }
/// <summary>
/// Interprets the result as a Nullable Double
/// </summary>
public static explicit operator double? (RedisResult result) { return result.AsNullableDouble(); }
/// <summary>
/// Interprets the result as a Nullable Int64
/// </summary>
public static explicit operator long? (RedisResult result) { return result.AsNullableInt64(); }
/// <summary>
/// Interprets the result as a Nullable Int32
/// </summary>
public static explicit operator int? (RedisResult result) { return result.AsNullableInt32(); }
/// <summary>
/// Interprets the result as a Nullable Boolean
/// </summary>
public static explicit operator bool? (RedisResult result) { return result.AsNullableBoolean(); }
/// <summary>
/// Interprets the result as an array of String
/// </summary>
public static explicit operator string[] (RedisResult result) { return result.AsStringArray(); }
/// <summary>
/// Interprets the result as an array of Byte[]
/// </summary>
public static explicit operator byte[][] (RedisResult result) { return result.AsByteArrayArray(); }
/// <summary>
/// Interprets the result as an array of Double
/// </summary>
public static explicit operator double[] (RedisResult result) { return result.AsDoubleArray(); }
/// <summary>
/// Interprets the result as an array of Int64
/// </summary>
public static explicit operator long[] (RedisResult result) { return result.AsInt64Array(); }
/// <summary>
/// Interprets the result as an array of Int32
/// </summary>
public static explicit operator int[] (RedisResult result) { return result.AsInt32Array(); }
/// <summary>
/// Interprets the result as an array of Boolean
/// </summary>
public static explicit operator bool[] (RedisResult result) { return result.AsBooleanArray(); }
/// <summary>
/// Interprets the result as an array of RedisValue
/// </summary>
public static explicit operator RedisValue[] (RedisResult result) { return result.AsRedisValueArray(); }
/// <summary>
/// Interprets the result as an array of RedisKey
/// </summary>
public static explicit operator RedisKey[] (RedisResult result) { return result.AsRedisKeyArray(); }
/// <summary>
/// Interprets the result as an array of RedisResult
/// </summary>
public static explicit operator RedisResult[] (RedisResult result) { return result.AsRedisResultArray(); }
internal abstract bool AsBoolean();
internal abstract bool[] AsBooleanArray();
internal abstract byte[] AsByteArray();
internal abstract byte[][] AsByteArrayArray();
internal abstract double AsDouble();
internal abstract double[] AsDoubleArray();
internal abstract int AsInt32();
internal abstract int[] AsInt32Array();
internal abstract long AsInt64();
internal abstract long[] AsInt64Array();
internal abstract bool? AsNullableBoolean();
internal abstract double? AsNullableDouble();
internal abstract int? AsNullableInt32();
internal abstract long? AsNullableInt64();
internal abstract RedisKey AsRedisKey();
internal abstract RedisKey[] AsRedisKeyArray();
internal abstract RedisResult[] AsRedisResultArray();
internal abstract RedisValue AsRedisValue();
internal abstract RedisValue[] AsRedisValueArray();
internal abstract string AsString();
internal abstract string[] AsStringArray();
private sealed class ArrayRedisResult : RedisResult
{
public override bool IsNull
{
get { return value == null; }
}
private readonly RedisResult[] value;
public ArrayRedisResult(RedisResult[] value)
{
if (value == null) throw new ArgumentNullException("value");
this.value = value;
}
public override string ToString()
{
return value.Length + " element(s)";
}
internal override bool AsBoolean()
{
if (value.Length == 1) return value[0].AsBoolean();
throw new InvalidCastException();
}
internal override bool[] AsBooleanArray() { return ConvertHelper.ConvertAll(value, x => x.AsBoolean()); }
internal override byte[] AsByteArray()
{
if (value.Length == 1) return value[0].AsByteArray();
throw new InvalidCastException();
}
internal override byte[][] AsByteArrayArray() { return ConvertHelper.ConvertAll(value, x => x.AsByteArray()); }
internal override double AsDouble()
{
if (value.Length == 1) return value[0].AsDouble();
throw new InvalidCastException();
}
internal override double[] AsDoubleArray() { return ConvertHelper.ConvertAll(value, x => x.AsDouble()); }
internal override int AsInt32()
{
if (value.Length == 1) return value[0].AsInt32();
throw new InvalidCastException();
}
internal override int[] AsInt32Array() { return ConvertHelper.ConvertAll(value, x => x.AsInt32()); }
internal override long AsInt64()
{
if (value.Length == 1) return value[0].AsInt64();
throw new InvalidCastException();
}
internal override long[] AsInt64Array() { return ConvertHelper.ConvertAll(value, x => x.AsInt64()); }
internal override bool? AsNullableBoolean()
{
if (value.Length == 1) return value[0].AsNullableBoolean();
throw new InvalidCastException();
}
internal override double? AsNullableDouble()
{
if (value.Length == 1) return value[0].AsNullableDouble();
throw new InvalidCastException();
}
internal override int? AsNullableInt32()
{
if (value.Length == 1) return value[0].AsNullableInt32();
throw new InvalidCastException();
}
internal override long? AsNullableInt64()
{
if (value.Length == 1) return value[0].AsNullableInt64();
throw new InvalidCastException();
}
internal override RedisKey AsRedisKey()
{
if (value.Length == 1) return value[0].AsRedisKey();
throw new InvalidCastException();
}
internal override RedisKey[] AsRedisKeyArray() { return ConvertHelper.ConvertAll(value, x => x.AsRedisKey()); }
internal override RedisResult[] AsRedisResultArray() { return value; }
internal override RedisValue AsRedisValue()
{
if (value.Length == 1) return value[0].AsRedisValue();
throw new InvalidCastException();
}
internal override RedisValue[] AsRedisValueArray() { return ConvertHelper.ConvertAll(value, x => x.AsRedisValue()); }
internal override string AsString()
{
if (value.Length == 1) return value[0].AsString();
throw new InvalidCastException();
}
internal override string[] AsStringArray() { return ConvertHelper.ConvertAll(value, x => x.AsString()); }
}
private sealed class ErrorRedisResult : RedisResult
{
private readonly string value;
public ErrorRedisResult(string value)
{
if (value == null) throw new ArgumentNullException("value");
this.value = value;
}
public override bool IsNull
{
get { return value == null; }
}
public override string ToString() { return value; }
internal override bool AsBoolean() { throw new RedisServerException(value); }
internal override bool[] AsBooleanArray() { throw new RedisServerException(value); }
internal override byte[] AsByteArray() { throw new RedisServerException(value); }
internal override byte[][] AsByteArrayArray() { throw new RedisServerException(value); }
internal override double AsDouble() { throw new RedisServerException(value); }
internal override double[] AsDoubleArray() { throw new RedisServerException(value); }
internal override int AsInt32() { throw new RedisServerException(value); }
internal override int[] AsInt32Array() { throw new RedisServerException(value); }
internal override long AsInt64() { throw new RedisServerException(value); }
internal override long[] AsInt64Array() { throw new RedisServerException(value); }
internal override bool? AsNullableBoolean() { throw new RedisServerException(value); }
internal override double? AsNullableDouble() { throw new RedisServerException(value); }
internal override int? AsNullableInt32() { throw new RedisServerException(value); }
internal override long? AsNullableInt64() { throw new RedisServerException(value); }
internal override RedisKey AsRedisKey() { throw new RedisServerException(value); }
internal override RedisKey[] AsRedisKeyArray() { throw new RedisServerException(value); }
internal override RedisResult[] AsRedisResultArray() { throw new RedisServerException(value); }
internal override RedisValue AsRedisValue() { throw new RedisServerException(value); }
internal override RedisValue[] AsRedisValueArray() { throw new RedisServerException(value); }
internal override string AsString() { throw new RedisServerException(value); }
internal override string[] AsStringArray() { throw new RedisServerException(value); }
}
private sealed class SingleRedisResult : RedisResult
{
private readonly RedisValue value;
public SingleRedisResult(RedisValue value)
{
this.value = value;
}
public override bool IsNull
{
get { return value.IsNull; }
}
public override string ToString() { return value.ToString(); }
internal override bool AsBoolean() { return (bool)value; }
internal override bool[] AsBooleanArray() { return new[] { AsBoolean() }; }
internal override byte[] AsByteArray() { return (byte[])value; }
internal override byte[][] AsByteArrayArray() { return new[] { AsByteArray() }; }
internal override double AsDouble() { return (double)value; }
internal override double[] AsDoubleArray() { return new[] { AsDouble() }; }
internal override int AsInt32() { return (int)value; }
internal override int[] AsInt32Array() { return new[] { AsInt32() }; }
internal override long AsInt64() { return (long)value; }
internal override long[] AsInt64Array() { return new[] { AsInt64() }; }
internal override bool? AsNullableBoolean() { return (bool?)value; }
internal override double? AsNullableDouble() { return (double?)value; }
internal override int? AsNullableInt32() { return (int?)value; }
internal override long? AsNullableInt64() { return (long?)value; }
internal override RedisKey AsRedisKey() { return (byte[])value; }
internal override RedisKey[] AsRedisKeyArray() { return new[] { AsRedisKey() }; }
internal override RedisResult[] AsRedisResultArray() { throw new InvalidCastException(); }
internal override RedisValue AsRedisValue() { return value; }
internal override RedisValue[] AsRedisValueArray() { return new[] { AsRedisValue() }; }
internal override string AsString() { return (string)value; }
internal override string[] AsStringArray() { return new[] { AsString() }; }
}
}
}
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Runtime.CompilerServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
namespace StackExchange.Redis
{
[Flags]
internal enum UnselectableFlags
{
None = 0,
RedundantMaster = 1,
DidNotRespond = 2,
ServerType = 4
}
internal sealed partial class ServerEndPoint : IDisposable
{
internal volatile ServerEndPoint Master;
internal volatile ServerEndPoint[] Slaves = NoSlaves;
private static readonly Regex nameSanitizer = new Regex("[^!-~]", InternalRegexCompiledOption.Default);
private static readonly ServerEndPoint[] NoSlaves = new ServerEndPoint[0];
private readonly EndPoint endpoint;
private readonly Hashtable knownScripts = new Hashtable(StringComparer.Ordinal);
private readonly ConnectionMultiplexer multiplexer;
private int databases, writeEverySeconds;
private PhysicalBridge interactive, subscription;
bool isDisposed;
ServerType serverType;
private bool slaveReadOnly, isSlave;
private volatile UnselectableFlags unselectableReasons;
private Version version;
internal void ResetNonConnected()
{
var tmp = interactive;
if (tmp != null) tmp.ResetNonConnected();
tmp = subscription;
if (tmp != null) tmp.ResetNonConnected();
}
public ServerEndPoint(ConnectionMultiplexer multiplexer, EndPoint endpoint, TextWriter log)
{
this.multiplexer = multiplexer;
this.endpoint = endpoint;
var config = multiplexer.RawConfig;
version = config.DefaultVersion;
slaveReadOnly = true;
isSlave = false;
databases = 0;
writeEverySeconds = config.KeepAlive > 0 ? config.KeepAlive : 60;
interactive = CreateBridge(ConnectionType.Interactive, log);
serverType = ServerType.Standalone;
// overrides for twemproxy
if (multiplexer.RawConfig.Proxy == Proxy.Twemproxy)
{
databases = 1;
serverType = ServerType.Twemproxy;
}
}
public ClusterConfiguration ClusterConfiguration { get; private set; }
public int Databases { get { return databases; } set { SetConfig(ref databases, value); } }
public EndPoint EndPoint { get { return endpoint; } }
public bool HasDatabases { get { return serverType == ServerType.Standalone; } }
public bool IsConnected
{
get
{
var tmp = interactive;
return tmp != null && tmp.IsConnected;
}
}
public bool IsSlave { get { return isSlave; } set { SetConfig(ref isSlave, value); } }
public long OperationCount
{
get
{
long total = 0;
var tmp = interactive;
if (tmp != null) total += tmp.OperationCount;
tmp = subscription;
if (tmp != null) total += tmp.OperationCount;
return total;
}
}
public bool RequiresReadMode { get { return serverType == ServerType.Cluster && IsSlave; } }
public ServerType ServerType { get { return serverType; } set { SetConfig(ref serverType, value); } }
public bool SlaveReadOnly { get { return slaveReadOnly; } set { SetConfig(ref slaveReadOnly, value); } }
public bool AllowSlaveWrites { get; set; }
public Version Version { get { return version; } set { SetConfig(ref version, value); } }
public int WriteEverySeconds { get { return writeEverySeconds; } set { SetConfig(ref writeEverySeconds, value); } }
internal ConnectionMultiplexer Multiplexer { get { return multiplexer; } }
public void ClearUnselectable(UnselectableFlags flags)
{
var oldFlags = unselectableReasons;
if (oldFlags != 0)
{
unselectableReasons &= ~flags;
if (unselectableReasons != oldFlags)
{
multiplexer.Trace(unselectableReasons == 0 ? "Now usable" : ("Now unusable: " + flags), ToString());
}
}
}
public void Dispose()
{
isDisposed = true;
var tmp = interactive;
interactive = null;
if (tmp != null) tmp.Dispose();
tmp = subscription;
subscription = null;
if (tmp != null) tmp.Dispose();
}
public PhysicalBridge GetBridge(ConnectionType type, bool create = true, TextWriter log = null)
{
if (isDisposed) return null;
switch (type)
{
case ConnectionType.Interactive:
return interactive ?? (create ? interactive = CreateBridge(ConnectionType.Interactive, log) : null);
case ConnectionType.Subscription:
return subscription ?? (create ? subscription = CreateBridge(ConnectionType.Subscription, log) : null);
}
return null;
}
public PhysicalBridge GetBridge(RedisCommand command, bool create = true)
{
if (isDisposed) return null;
switch (command)
{
case RedisCommand.SUBSCRIBE:
case RedisCommand.UNSUBSCRIBE:
case RedisCommand.PSUBSCRIBE:
case RedisCommand.PUNSUBSCRIBE:
return subscription ?? (create ? subscription = CreateBridge(ConnectionType.Subscription, null) : null);
default:
return interactive;
}
}
public RedisFeatures GetFeatures()
{
return new RedisFeatures(version);
}
public void SetClusterConfiguration(ClusterConfiguration configuration)
{
ClusterConfiguration = configuration;
if (configuration != null)
{
multiplexer.Trace("Updating cluster ranges...");
multiplexer.UpdateClusterRange(configuration);
multiplexer.Trace("Resolving genealogy...");
var thisNode = configuration.Nodes.FirstOrDefault(x => x.EndPoint == this.EndPoint);
if (thisNode != null)
{
List<ServerEndPoint> slaves = null;
ServerEndPoint master = null;
foreach (var node in configuration.Nodes)
{
if (node.NodeId == thisNode.ParentNodeId)
{
master = multiplexer.GetServerEndPoint(node.EndPoint);
}
else if (node.ParentNodeId == thisNode.NodeId)
{
if (slaves == null) slaves = new List<ServerEndPoint>();
slaves.Add(multiplexer.GetServerEndPoint(node.EndPoint));
}
}
Master = master;
Slaves = slaves == null ? NoSlaves : slaves.ToArray();
}
multiplexer.Trace("Cluster configured");
}
}
public void SetUnselectable(UnselectableFlags flags)
{
if (flags != 0)
{
var oldFlags = unselectableReasons;
unselectableReasons |= flags;
if (unselectableReasons != oldFlags)
{
multiplexer.Trace(unselectableReasons == 0 ? "Now usable" : ("Now unusable: " + flags), ToString());
}
}
}
public override string ToString()
{
return Format.ToString(EndPoint);
}
public bool TryEnqueue(Message message)
{
var bridge = GetBridge(message.Command);
return bridge != null && bridge.TryEnqueue(message, isSlave);
}
internal void Activate(ConnectionType type, TextWriter log)
{
GetBridge(type, true, log);
}
internal void AddScript(string script, byte[] hash)
{
lock (knownScripts)
{
knownScripts[script] = hash;
}
}
internal void AutoConfigure(PhysicalConnection connection)
{
if (serverType == ServerType.Twemproxy)
{
// don't try to detect configuration; all the config commands are disabled, and
// the fallback master/slave detection won't help
return;
}
var commandMap = multiplexer.CommandMap;
const CommandFlags flags = CommandFlags.FireAndForget | CommandFlags.HighPriority | CommandFlags.NoRedirect;
var features = GetFeatures();
Message msg;
if (commandMap.IsAvailable(RedisCommand.CONFIG))
{
if (multiplexer.RawConfig.KeepAlive <= 0)
{
msg = Message.Create(-1, flags, RedisCommand.CONFIG, RedisLiterals.GET, RedisLiterals.timeout);
msg.SetInternalCall();
WriteDirectOrQueueFireAndForget(connection, msg, ResultProcessor.AutoConfigure);
}
msg = Message.Create(-1, flags, RedisCommand.CONFIG, RedisLiterals.GET, RedisLiterals.slave_read_only);
msg.SetInternalCall();
WriteDirectOrQueueFireAndForget(connection, msg, ResultProcessor.AutoConfigure);
msg = Message.Create(-1, flags, RedisCommand.CONFIG, RedisLiterals.GET, RedisLiterals.databases);
msg.SetInternalCall();
WriteDirectOrQueueFireAndForget(connection, msg, ResultProcessor.AutoConfigure);
}
if (commandMap.IsAvailable(RedisCommand.INFO))
{
lastInfoReplicationCheckTicks = Environment.TickCount;
if (features.InfoSections)
{
msg = Message.Create(-1, flags, RedisCommand.INFO, RedisLiterals.replication);
msg.SetInternalCall();
WriteDirectOrQueueFireAndForget(connection, msg, ResultProcessor.AutoConfigure);
msg = Message.Create(-1, flags, RedisCommand.INFO, RedisLiterals.server);
msg.SetInternalCall();
WriteDirectOrQueueFireAndForget(connection, msg, ResultProcessor.AutoConfigure);
}
else
{
msg = Message.Create(-1, flags, RedisCommand.INFO);
msg.SetInternalCall();
WriteDirectOrQueueFireAndForget(connection, msg, ResultProcessor.AutoConfigure);
}
}
else if (commandMap.IsAvailable(RedisCommand.SET))
{
// this is a nasty way to find if we are a slave, and it will only work on up-level servers, but...
RedisKey key = Guid.NewGuid().ToByteArray();
msg = Message.Create(0, flags, RedisCommand.SET, key, RedisLiterals.slave_read_only, RedisLiterals.PX, 1, RedisLiterals.NX);
msg.SetInternalCall();
WriteDirectOrQueueFireAndForget(connection, msg, ResultProcessor.AutoConfigure);
}
if (commandMap.IsAvailable(RedisCommand.CLUSTER))
{
msg = Message.Create(-1, flags, RedisCommand.CLUSTER, RedisLiterals.NODES);
msg.SetInternalCall();
WriteDirectOrQueueFireAndForget(connection, msg, ResultProcessor.ClusterNodes);
}
}
internal Task Close()
{
var tmp = interactive;
Task result;
if (tmp == null || !tmp.IsConnected || !multiplexer.CommandMap.IsAvailable(RedisCommand.QUIT))
{
result = CompletedTask<bool>.Default(null);
}
else
{
result = QueueDirectAsync(Message.Create(-1, CommandFlags.None, RedisCommand.QUIT), ResultProcessor.DemandOK, bridge: interactive);
}
return result;
}
internal void FlushScriptCache()
{
lock (knownScripts)
{
knownScripts.Clear();
}
}
private string runId;
internal string RunId
{
get { return runId; }
set
{
if (value != runId) // we only care about changes
{
// if we had an old run-id, and it has changed, then the
// server has been restarted; which means the script cache
// is toast
if (runId != null) FlushScriptCache();
runId = value;
}
}
}
internal ServerCounters GetCounters()
{
var counters = new ServerCounters(endpoint);
var tmp = interactive;
if (tmp != null) tmp.GetCounters(counters.Interactive);
tmp = subscription;
if (tmp != null) tmp.GetCounters(counters.Subscription);
return counters;
}
internal int GetOutstandingCount(RedisCommand command, out int inst, out int qu, out int qs, out int qc, out int wr, out int wq, out int @in, out int ar)
{
var bridge = GetBridge(command, false);
if (bridge == null)
{
return inst = qu = qs = qc = wr = wq = @in = ar = 0;
}
return bridge.GetOutstandingCount(out inst, out qu, out qs, out qc, out wr, out wq, out @in, out ar);
}
internal string GetProfile()
{
var sb = new StringBuilder();
sb.Append("Circular op-count snapshot; int:");
var tmp = interactive;
if (tmp != null) tmp.AppendProfile(sb);
sb.Append("; sub:");
tmp = subscription;
if (tmp != null) tmp.AppendProfile(sb);
return sb.ToString();
}
internal byte[] GetScriptHash(string script, RedisCommand command)
{
var found = (byte[])knownScripts[script];
if(found == null && command == RedisCommand.EVALSHA)
{
// the script provided is a hex sha; store and re-use the ascii for that
found = Encoding.ASCII.GetBytes(script);
lock(knownScripts)
{
knownScripts[script] = found;
}
}
return found;
}
internal string GetStormLog(RedisCommand command)
{
var bridge = GetBridge(command);
return bridge == null ? null : bridge.GetStormLog();
}
internal Message GetTracerMessage(bool assertIdentity)
{
// different configurations block certain commands, as can ad-hoc local configurations, so
// we'll do the best with what we have available.
// note that the muxer-ctor asserts that one of ECHO, PING, TIME of GET is available
// see also: TracerProcessor
var map = multiplexer.CommandMap;
Message msg;
const CommandFlags flags = CommandFlags.NoRedirect | CommandFlags.FireAndForget;
if (assertIdentity && map.IsAvailable(RedisCommand.ECHO))
{
msg = Message.Create(-1, flags, RedisCommand.ECHO, (RedisValue)multiplexer.UniqueId);
}
else if (map.IsAvailable(RedisCommand.PING))
{
msg = Message.Create(-1, flags, RedisCommand.PING);
}
else if (map.IsAvailable(RedisCommand.TIME))
{
msg = Message.Create(-1, flags, RedisCommand.TIME);
}
else if (!assertIdentity && map.IsAvailable(RedisCommand.ECHO))
{
// we'll use echo as a PING substitute if it is all we have (in preference to EXISTS)
msg = Message.Create(-1, flags, RedisCommand.ECHO, (RedisValue)multiplexer.UniqueId);
}
else
{
map.AssertAvailable(RedisCommand.EXISTS);
msg = Message.Create(0, flags, RedisCommand.EXISTS, (RedisValue)multiplexer.UniqueId);
}
msg.SetInternalCall();
return msg;
}
internal bool IsSelectable(RedisCommand command)
{
var bridge = unselectableReasons == 0 ? GetBridge(command, false) : null;
return bridge != null && bridge.IsConnected;
}
internal void OnEstablishing(PhysicalConnection connection, TextWriter log)
{
try
{
if (connection == null) return;
Handshake(connection, log);
}
catch (Exception ex)
{
connection.RecordConnectionFailed(ConnectionFailureType.InternalFailure, ex);
}
}
internal void OnFullyEstablished(PhysicalConnection connection)
{
try
{
if (connection == null) return;
var bridge = connection.Bridge;
if (bridge == subscription)
{
multiplexer.ResendSubscriptions(this);
}
multiplexer.OnConnectionRestored(endpoint, bridge.ConnectionType);
}
catch (Exception ex)
{
connection.RecordConnectionFailed(ConnectionFailureType.InternalFailure, ex);
}
}
internal int LastInfoReplicationCheckSecondsAgo
{
get { return unchecked(Environment.TickCount - VolatileWrapper.Read(ref lastInfoReplicationCheckTicks)) / 1000; }
}
private EndPoint masterEndPoint;
public EndPoint MasterEndPoint
{
get { return masterEndPoint; }
set { SetConfig(ref masterEndPoint, value); }
}
internal bool CheckInfoReplication()
{
lastInfoReplicationCheckTicks = Environment.TickCount;
PhysicalBridge bridge;
if (version >= RedisFeatures.v2_8_0 && multiplexer.CommandMap.IsAvailable(RedisCommand.INFO)
&& (bridge = GetBridge(ConnectionType.Interactive, false)) != null)
{
var msg = Message.Create(-1, CommandFlags.FireAndForget | CommandFlags.HighPriority | CommandFlags.NoRedirect, RedisCommand.INFO, RedisLiterals.replication);
msg.SetInternalCall();
QueueDirectFireAndForget(msg, ResultProcessor.AutoConfigure, bridge);
return true;
}
return false;
}
private int lastInfoReplicationCheckTicks;
internal void OnHeartbeat()
{
try
{
var tmp = interactive;
if (tmp != null) tmp.OnHeartbeat(false);
tmp = subscription;
if (tmp != null) tmp.OnHeartbeat(false);
} catch(Exception ex)
{
multiplexer.OnInternalError(ex, EndPoint);
}
}
internal Task<T> QueueDirectAsync<T>(Message message, ResultProcessor<T> processor, object asyncState = null, PhysicalBridge bridge = null)
{
var tcs = TaskSource.CreateDenyExecSync<T>(asyncState);
var source = ResultBox<T>.Get(tcs);
message.SetSource(processor, source);
if (bridge == null) bridge = GetBridge(message.Command);
if (!bridge.TryEnqueue(message, isSlave))
{
ConnectionMultiplexer.ThrowFailed(tcs, ExceptionFactory.NoConnectionAvailable(multiplexer.IncludeDetailInExceptions, message.Command, message, this));
}
return tcs.Task;
}
internal void QueueDirectFireAndForget<T>(Message message, ResultProcessor<T> processor, PhysicalBridge bridge = null)
{
if (message != null)
{
message.SetSource(processor, null);
multiplexer.Trace("Enqueue: " + message);
(bridge ?? GetBridge(message.Command)).TryEnqueue(message, isSlave);
}
}
internal void ReportNextFailure()
{
var tmp = interactive;
if (tmp != null) tmp.ReportNextFailure();
tmp = subscription;
if (tmp != null) tmp.ReportNextFailure();
}
internal Task<bool> SendTracer(TextWriter log = null)
{
var msg = GetTracerMessage(false);
msg = LoggingMessage.Create(log, msg);
return QueueDirectAsync(msg, ResultProcessor.Tracer);
}
internal string Summary()
{
var sb = new StringBuilder(Format.ToString(endpoint))
.Append(": ").Append(serverType).Append(" v").Append(version).Append(", ").Append(isSlave ? "slave" : "master");
if (databases > 0) sb.Append("; ").Append(databases).Append(" databases");
if (writeEverySeconds > 0)
sb.Append("; keep-alive: ").Append(TimeSpan.FromSeconds(writeEverySeconds));
var tmp = interactive;
sb.Append("; int: ").Append(tmp == null ? "n/a" : tmp.ConnectionState.ToString());
tmp = subscription;
if(tmp == null)
{
sb.Append("; sub: n/a");
} else
{
var state = tmp.ConnectionState;
sb.Append("; sub: ").Append(state);
if(state == PhysicalBridge.State.ConnectedEstablished)
{
sb.Append(", ").Append(tmp.SubscriptionCount).Append(" active");
}
}
var flags = unselectableReasons;
if (flags != 0)
{
sb.Append("; not in use: ").Append(flags);
}
return sb.ToString();
}
internal void WriteDirectOrQueueFireAndForget<T>(PhysicalConnection connection, Message message, ResultProcessor<T> processor)
{
if (message != null)
{
message.SetSource(processor, null);
if (connection == null)
{
multiplexer.Trace("Enqueue: " + message);
GetBridge(message.Command).TryEnqueue(message, isSlave);
}
else
{
multiplexer.Trace("Writing direct: " + message);
connection.Bridge.WriteMessageDirect(connection, message);
}
}
}
private PhysicalBridge CreateBridge(ConnectionType type, TextWriter log)
{
multiplexer.Trace(type.ToString());
var bridge = new PhysicalBridge(this, type);
bridge.TryConnect(log);
return bridge;
}
void Handshake(PhysicalConnection connection, TextWriter log)
{
multiplexer.LogLocked(log, "Server handshake");
if (connection == null)
{
multiplexer.Trace("No connection!?");
return;
}
Message msg;
string password = multiplexer.RawConfig.Password;
if (!string.IsNullOrWhiteSpace(password))
{
multiplexer.LogLocked(log, "Authenticating (password)");
msg = Message.Create(-1, CommandFlags.FireAndForget, RedisCommand.AUTH, (RedisValue)password);
msg.SetInternalCall();
WriteDirectOrQueueFireAndForget(connection, msg, ResultProcessor.DemandOK);
}
if (multiplexer.CommandMap.IsAvailable(RedisCommand.CLIENT))
{
string name = multiplexer.ClientName;
if (!string.IsNullOrWhiteSpace(name))
{
name = nameSanitizer.Replace(name, "");
if (!string.IsNullOrWhiteSpace(name))
{
multiplexer.LogLocked(log, "Setting client name: {0}", name);
msg = Message.Create(-1, CommandFlags.FireAndForget, RedisCommand.CLIENT, RedisLiterals.SETNAME, (RedisValue)name);
msg.SetInternalCall();
WriteDirectOrQueueFireAndForget(connection, msg, ResultProcessor.DemandOK);
}
}
}
var connType = connection.Bridge.ConnectionType;
if (connType == ConnectionType.Interactive)
{
multiplexer.LogLocked(log, "Auto-configure...");
AutoConfigure(connection);
}
multiplexer.LogLocked(log, "Sending critical tracer: {0}", connection.Bridge);
var tracer = GetTracerMessage(true);
tracer = LoggingMessage.Create(log, tracer);
WriteDirectOrQueueFireAndForget(connection, tracer, ResultProcessor.EstablishConnection);
// note: this **must** be the last thing on the subscription handshake, because after this
// we will be in subscriber mode: regular commands cannot be sent
if (connType == ConnectionType.Subscription)
{
var configChannel = multiplexer.ConfigurationChangedChannel;
if(configChannel != null)
{
msg = Message.Create(-1, CommandFlags.FireAndForget, RedisCommand.SUBSCRIBE, (RedisChannel)configChannel);
WriteDirectOrQueueFireAndForget(connection, msg, ResultProcessor.TrackSubscriptions);
}
}
multiplexer.LogLocked(log, "Flushing outbound buffer");
connection.Flush();
}
private void SetConfig<T>(ref T field, T value, [CallerMemberName] string caller = null)
{
if(!EqualityComparer<T>.Default.Equals(field, value))
{
multiplexer.Trace(caller + " changed from " + field + " to " + value, "Configuration");
field = value;
multiplexer.ReconfigureIfNeeded(endpoint, false, caller);
}
}
}
}
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Runtime.CompilerServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
namespace StackExchange.Redis
{
[Flags]
internal enum UnselectableFlags
{
None = 0,
RedundantMaster = 1,
DidNotRespond = 2,
ServerType = 4
}
internal sealed partial class ServerEndPoint : IDisposable
{
internal volatile ServerEndPoint Master;
internal volatile ServerEndPoint[] Slaves = NoSlaves;
private static readonly Regex nameSanitizer = new Regex("[^!-~]", InternalRegexCompiledOption.Default);
private static readonly ServerEndPoint[] NoSlaves = new ServerEndPoint[0];
private readonly EndPoint endpoint;
private readonly Hashtable knownScripts = new Hashtable(StringComparer.Ordinal);
private readonly ConnectionMultiplexer multiplexer;
private int databases, writeEverySeconds;
private PhysicalBridge interactive, subscription;
bool isDisposed;
ServerType serverType;
private bool slaveReadOnly, isSlave;
private volatile UnselectableFlags unselectableReasons;
private Version version;
internal void ResetNonConnected()
{
var tmp = interactive;
if (tmp != null) tmp.ResetNonConnected();
tmp = subscription;
if (tmp != null) tmp.ResetNonConnected();
}
public ServerEndPoint(ConnectionMultiplexer multiplexer, EndPoint endpoint, TextWriter log)
{
this.multiplexer = multiplexer;
this.endpoint = endpoint;
var config = multiplexer.RawConfig;
version = config.DefaultVersion;
slaveReadOnly = true;
isSlave = false;
databases = 0;
writeEverySeconds = config.KeepAlive > 0 ? config.KeepAlive : 60;
interactive = CreateBridge(ConnectionType.Interactive, log);
serverType = ServerType.Standalone;
// overrides for twemproxy
if (multiplexer.RawConfig.Proxy == Proxy.Twemproxy)
{
databases = 1;
serverType = ServerType.Twemproxy;
}
}
public ClusterConfiguration ClusterConfiguration { get; private set; }
public int Databases { get { return databases; } set { SetConfig(ref databases, value); } }
public EndPoint EndPoint { get { return endpoint; } }
public bool HasDatabases { get { return serverType == ServerType.Standalone; } }
public bool IsConnected
{
get
{
var tmp = interactive;
return tmp != null && tmp.IsConnected;
}
}
public bool IsSlave { get { return isSlave; } set { SetConfig(ref isSlave, value); } }
public long OperationCount
{
get
{
long total = 0;
var tmp = interactive;
if (tmp != null) total += tmp.OperationCount;
tmp = subscription;
if (tmp != null) total += tmp.OperationCount;
return total;
}
}
public bool RequiresReadMode { get { return serverType == ServerType.Cluster && IsSlave; } }
public ServerType ServerType { get { return serverType; } set { SetConfig(ref serverType, value); } }
public bool SlaveReadOnly { get { return slaveReadOnly; } set { SetConfig(ref slaveReadOnly, value); } }
public bool AllowSlaveWrites { get; set; }
public Version Version { get { return version; } set { SetConfig(ref version, value); } }
public int WriteEverySeconds { get { return writeEverySeconds; } set { SetConfig(ref writeEverySeconds, value); } }
internal ConnectionMultiplexer Multiplexer { get { return multiplexer; } }
public void ClearUnselectable(UnselectableFlags flags)
{
var oldFlags = unselectableReasons;
if (oldFlags != 0)
{
unselectableReasons &= ~flags;
if (unselectableReasons != oldFlags)
{
multiplexer.Trace(unselectableReasons == 0 ? "Now usable" : ("Now unusable: " + flags), ToString());
}
}
}
public void Dispose()
{
isDisposed = true;
var tmp = interactive;
interactive = null;
if (tmp != null) tmp.Dispose();
tmp = subscription;
subscription = null;
if (tmp != null) tmp.Dispose();
}
public PhysicalBridge GetBridge(ConnectionType type, bool create = true, TextWriter log = null)
{
if (isDisposed) return null;
switch (type)
{
case ConnectionType.Interactive:
return interactive ?? (create ? interactive = CreateBridge(ConnectionType.Interactive, log) : null);
case ConnectionType.Subscription:
return subscription ?? (create ? subscription = CreateBridge(ConnectionType.Subscription, log) : null);
}
return null;
}
public PhysicalBridge GetBridge(RedisCommand command, bool create = true)
{
if (isDisposed) return null;
switch (command)
{
case RedisCommand.SUBSCRIBE:
case RedisCommand.UNSUBSCRIBE:
case RedisCommand.PSUBSCRIBE:
case RedisCommand.PUNSUBSCRIBE:
return subscription ?? (create ? subscription = CreateBridge(ConnectionType.Subscription, null) : null);
default:
return interactive;
}
}
public RedisFeatures GetFeatures()
{
return new RedisFeatures(version);
}
public void SetClusterConfiguration(ClusterConfiguration configuration)
{
ClusterConfiguration = configuration;
if (configuration != null)
{
multiplexer.Trace("Updating cluster ranges...");
multiplexer.UpdateClusterRange(configuration);
multiplexer.Trace("Resolving genealogy...");
var thisNode = configuration.Nodes.FirstOrDefault(x => x.EndPoint == this.EndPoint);
if (thisNode != null)
{
List<ServerEndPoint> slaves = null;
ServerEndPoint master = null;
foreach (var node in configuration.Nodes)
{
if (node.NodeId == thisNode.ParentNodeId)
{
master = multiplexer.GetServerEndPoint(node.EndPoint);
}
else if (node.ParentNodeId == thisNode.NodeId)
{
if (slaves == null) slaves = new List<ServerEndPoint>();
slaves.Add(multiplexer.GetServerEndPoint(node.EndPoint));
}
}
Master = master;
Slaves = slaves == null ? NoSlaves : slaves.ToArray();
}
multiplexer.Trace("Cluster configured");
}
}
public void SetUnselectable(UnselectableFlags flags)
{
if (flags != 0)
{
var oldFlags = unselectableReasons;
unselectableReasons |= flags;
if (unselectableReasons != oldFlags)
{
multiplexer.Trace(unselectableReasons == 0 ? "Now usable" : ("Now unusable: " + flags), ToString());
}
}
}
public override string ToString()
{
return Format.ToString(EndPoint);
}
public bool TryEnqueue(Message message)
{
var bridge = GetBridge(message.Command);
return bridge != null && bridge.TryEnqueue(message, isSlave);
}
internal void Activate(ConnectionType type, TextWriter log)
{
GetBridge(type, true, log);
}
internal void AddScript(string script, byte[] hash)
{
lock (knownScripts)
{
knownScripts[script] = hash;
}
}
internal void AutoConfigure(PhysicalConnection connection)
{
if (serverType == ServerType.Twemproxy)
{
// don't try to detect configuration; all the config commands are disabled, and
// the fallback master/slave detection won't help
return;
}
var commandMap = multiplexer.CommandMap;
const CommandFlags flags = CommandFlags.FireAndForget | CommandFlags.HighPriority | CommandFlags.NoRedirect;
var features = GetFeatures();
Message msg;
if (commandMap.IsAvailable(RedisCommand.CONFIG))
{
if (multiplexer.RawConfig.KeepAlive <= 0)
{
msg = Message.Create(-1, flags, RedisCommand.CONFIG, RedisLiterals.GET, RedisLiterals.timeout);
msg.SetInternalCall();
WriteDirectOrQueueFireAndForget(connection, msg, ResultProcessor.AutoConfigure);
}
msg = Message.Create(-1, flags, RedisCommand.CONFIG, RedisLiterals.GET, RedisLiterals.slave_read_only);
msg.SetInternalCall();
WriteDirectOrQueueFireAndForget(connection, msg, ResultProcessor.AutoConfigure);
msg = Message.Create(-1, flags, RedisCommand.CONFIG, RedisLiterals.GET, RedisLiterals.databases);
msg.SetInternalCall();
WriteDirectOrQueueFireAndForget(connection, msg, ResultProcessor.AutoConfigure);
}
if (commandMap.IsAvailable(RedisCommand.INFO))
{
lastInfoReplicationCheckTicks = Environment.TickCount;
if (features.InfoSections)
{
msg = Message.Create(-1, flags, RedisCommand.INFO, RedisLiterals.replication);
msg.SetInternalCall();
WriteDirectOrQueueFireAndForget(connection, msg, ResultProcessor.AutoConfigure);
msg = Message.Create(-1, flags, RedisCommand.INFO, RedisLiterals.server);
msg.SetInternalCall();
WriteDirectOrQueueFireAndForget(connection, msg, ResultProcessor.AutoConfigure);
}
else
{
msg = Message.Create(-1, flags, RedisCommand.INFO);
msg.SetInternalCall();
WriteDirectOrQueueFireAndForget(connection, msg, ResultProcessor.AutoConfigure);
}
}
else if (commandMap.IsAvailable(RedisCommand.SET))
{
// this is a nasty way to find if we are a slave, and it will only work on up-level servers, but...
RedisKey key = Guid.NewGuid().ToByteArray();
msg = Message.Create(0, flags, RedisCommand.SET, key, RedisLiterals.slave_read_only, RedisLiterals.PX, 1, RedisLiterals.NX);
msg.SetInternalCall();
WriteDirectOrQueueFireAndForget(connection, msg, ResultProcessor.AutoConfigure);
}
if (commandMap.IsAvailable(RedisCommand.CLUSTER))
{
msg = Message.Create(-1, flags, RedisCommand.CLUSTER, RedisLiterals.NODES);
msg.SetInternalCall();
WriteDirectOrQueueFireAndForget(connection, msg, ResultProcessor.ClusterNodes);
}
}
internal Task Close()
{
var tmp = interactive;
Task result;
if (tmp == null || !tmp.IsConnected || !multiplexer.CommandMap.IsAvailable(RedisCommand.QUIT))
{
result = CompletedTask<bool>.Default(null);
}
else
{
result = QueueDirectAsync(Message.Create(-1, CommandFlags.None, RedisCommand.QUIT), ResultProcessor.DemandOK, bridge: interactive);
}
return result;
}
internal void FlushScriptCache()
{
lock (knownScripts)
{
knownScripts.Clear();
}
}
private string runId;
internal string RunId
{
get { return runId; }
set
{
if (value != runId) // we only care about changes
{
// if we had an old run-id, and it has changed, then the
// server has been restarted; which means the script cache
// is toast
if (runId != null) FlushScriptCache();
runId = value;
}
}
}
internal ServerCounters GetCounters()
{
var counters = new ServerCounters(endpoint);
var tmp = interactive;
if (tmp != null) tmp.GetCounters(counters.Interactive);
tmp = subscription;
if (tmp != null) tmp.GetCounters(counters.Subscription);
return counters;
}
internal int GetOutstandingCount(RedisCommand command, out int inst, out int qu, out int qs, out int qc, out int wr, out int wq, out int @in, out int ar)
{
var bridge = GetBridge(command, false);
if (bridge == null)
{
return inst = qu = qs = qc = wr = wq = @in = ar = 0;
}
return bridge.GetOutstandingCount(out inst, out qu, out qs, out qc, out wr, out wq, out @in, out ar);
}
internal string GetProfile()
{
var sb = new StringBuilder();
sb.Append("Circular op-count snapshot; int:");
var tmp = interactive;
if (tmp != null) tmp.AppendProfile(sb);
sb.Append("; sub:");
tmp = subscription;
if (tmp != null) tmp.AppendProfile(sb);
return sb.ToString();
}
internal byte[] GetScriptHash(string script, RedisCommand command)
{
var found = (byte[])knownScripts[script];
if(found == null && command == RedisCommand.EVALSHA)
{
// the script provided is a hex sha; store and re-use the ascii for that
found = Encoding.ASCII.GetBytes(script);
lock(knownScripts)
{
knownScripts[script] = found;
}
}
return found;
}
internal string GetStormLog(RedisCommand command)
{
var bridge = GetBridge(command);
return bridge == null ? null : bridge.GetStormLog();
}
internal Message GetTracerMessage(bool assertIdentity)
{
// different configurations block certain commands, as can ad-hoc local configurations, so
// we'll do the best with what we have available.
// note that the muxer-ctor asserts that one of ECHO, PING, TIME of GET is available
// see also: TracerProcessor
var map = multiplexer.CommandMap;
Message msg;
const CommandFlags flags = CommandFlags.NoRedirect | CommandFlags.FireAndForget;
if (assertIdentity && map.IsAvailable(RedisCommand.ECHO))
{
msg = Message.Create(-1, flags, RedisCommand.ECHO, (RedisValue)multiplexer.UniqueId);
}
else if (map.IsAvailable(RedisCommand.PING))
{
msg = Message.Create(-1, flags, RedisCommand.PING);
}
else if (map.IsAvailable(RedisCommand.TIME))
{
msg = Message.Create(-1, flags, RedisCommand.TIME);
}
else if (!assertIdentity && map.IsAvailable(RedisCommand.ECHO))
{
// we'll use echo as a PING substitute if it is all we have (in preference to EXISTS)
msg = Message.Create(-1, flags, RedisCommand.ECHO, (RedisValue)multiplexer.UniqueId);
}
else
{
map.AssertAvailable(RedisCommand.EXISTS);
msg = Message.Create(0, flags, RedisCommand.EXISTS, (RedisValue)multiplexer.UniqueId);
}
msg.SetInternalCall();
return msg;
}
internal bool IsSelectable(RedisCommand command)
{
var bridge = unselectableReasons == 0 ? GetBridge(command, false) : null;
return bridge != null && bridge.IsConnected;
}
internal void OnEstablishing(PhysicalConnection connection, TextWriter log)
{
try
{
if (connection == null) return;
Handshake(connection, log);
}
catch (Exception ex)
{
connection.RecordConnectionFailed(ConnectionFailureType.InternalFailure, ex);
}
}
internal void OnFullyEstablished(PhysicalConnection connection)
{
try
{
if (connection == null) return;
var bridge = connection.Bridge;
if (bridge == subscription)
{
multiplexer.ResendSubscriptions(this);
}
multiplexer.OnConnectionRestored(endpoint, bridge.ConnectionType);
}
catch (Exception ex)
{
connection.RecordConnectionFailed(ConnectionFailureType.InternalFailure, ex);
}
}
internal int LastInfoReplicationCheckSecondsAgo
{
get { return unchecked(Environment.TickCount - VolatileWrapper.Read(ref lastInfoReplicationCheckTicks)) / 1000; }
}
private EndPoint masterEndPoint;
public EndPoint MasterEndPoint
{
get { return masterEndPoint; }
set { SetConfig(ref masterEndPoint, value); }
}
internal bool CheckInfoReplication()
{
lastInfoReplicationCheckTicks = Environment.TickCount;
PhysicalBridge bridge;
if (version >= RedisFeatures.v2_8_0 && multiplexer.CommandMap.IsAvailable(RedisCommand.INFO)
&& (bridge = GetBridge(ConnectionType.Interactive, false)) != null)
{
var msg = Message.Create(-1, CommandFlags.FireAndForget | CommandFlags.HighPriority | CommandFlags.NoRedirect, RedisCommand.INFO, RedisLiterals.replication);
msg.SetInternalCall();
QueueDirectFireAndForget(msg, ResultProcessor.AutoConfigure, bridge);
return true;
}
return false;
}
private int lastInfoReplicationCheckTicks;
internal void OnHeartbeat()
{
try
{
var tmp = interactive;
if (tmp != null) tmp.OnHeartbeat(false);
tmp = subscription;
if (tmp != null) tmp.OnHeartbeat(false);
} catch(Exception ex)
{
multiplexer.OnInternalError(ex, EndPoint);
}
}
internal Task<T> QueueDirectAsync<T>(Message message, ResultProcessor<T> processor, object asyncState = null, PhysicalBridge bridge = null)
{
var tcs = TaskSource.CreateDenyExecSync<T>(asyncState);
var source = ResultBox<T>.Get(tcs);
message.SetSource(processor, source);
if (bridge == null) bridge = GetBridge(message.Command);
if (!bridge.TryEnqueue(message, isSlave))
{
ConnectionMultiplexer.ThrowFailed(tcs, ExceptionFactory.NoConnectionAvailable(multiplexer.IncludeDetailInExceptions, message.Command, message, this));
}
return tcs.Task;
}
internal void QueueDirectFireAndForget<T>(Message message, ResultProcessor<T> processor, PhysicalBridge bridge = null)
{
if (message != null)
{
message.SetSource(processor, null);
multiplexer.Trace("Enqueue: " + message);
(bridge ?? GetBridge(message.Command)).TryEnqueue(message, isSlave);
}
}
internal void ReportNextFailure()
{
var tmp = interactive;
if (tmp != null) tmp.ReportNextFailure();
tmp = subscription;
if (tmp != null) tmp.ReportNextFailure();
}
internal Task<bool> SendTracer(TextWriter log = null)
{
var msg = GetTracerMessage(false);
msg = LoggingMessage.Create(log, msg);
return QueueDirectAsync(msg, ResultProcessor.Tracer);
}
internal string Summary()
{
var sb = new StringBuilder(Format.ToString(endpoint))
.Append(": ").Append(serverType).Append(" v").Append(version).Append(", ").Append(isSlave ? "slave" : "master");
if (databases > 0) sb.Append("; ").Append(databases).Append(" databases");
if (writeEverySeconds > 0)
sb.Append("; keep-alive: ").Append(TimeSpan.FromSeconds(writeEverySeconds));
var tmp = interactive;
sb.Append("; int: ").Append(tmp == null ? "n/a" : tmp.ConnectionState.ToString());
tmp = subscription;
if(tmp == null)
{
sb.Append("; sub: n/a");
} else
{
var state = tmp.ConnectionState;
sb.Append("; sub: ").Append(state);
if(state == PhysicalBridge.State.ConnectedEstablished)
{
sb.Append(", ").Append(tmp.SubscriptionCount).Append(" active");
}
}
var flags = unselectableReasons;
if (flags != 0)
{
sb.Append("; not in use: ").Append(flags);
}
return sb.ToString();
}
internal void WriteDirectOrQueueFireAndForget<T>(PhysicalConnection connection, Message message, ResultProcessor<T> processor)
{
if (message != null)
{
message.SetSource(processor, null);
if (connection == null)
{
multiplexer.Trace("Enqueue: " + message);
GetBridge(message.Command).TryEnqueue(message, isSlave);
}
else
{
multiplexer.Trace("Writing direct: " + message);
connection.Bridge.WriteMessageDirect(connection, message);
}
}
}
private PhysicalBridge CreateBridge(ConnectionType type, TextWriter log)
{
multiplexer.Trace(type.ToString());
var bridge = new PhysicalBridge(this, type);
bridge.TryConnect(log);
return bridge;
}
void Handshake(PhysicalConnection connection, TextWriter log)
{
multiplexer.LogLocked(log, "Server handshake");
if (connection == null)
{
multiplexer.Trace("No connection!?");
return;
}
Message msg;
string password = multiplexer.RawConfig.Password;
if (!string.IsNullOrWhiteSpace(password))
{
multiplexer.LogLocked(log, "Authenticating (password)");
msg = Message.Create(-1, CommandFlags.FireAndForget, RedisCommand.AUTH, (RedisValue)password);
msg.SetInternalCall();
WriteDirectOrQueueFireAndForget(connection, msg, ResultProcessor.DemandOK);
}
if (multiplexer.CommandMap.IsAvailable(RedisCommand.CLIENT))
{
string name = multiplexer.ClientName;
if (!string.IsNullOrWhiteSpace(name))
{
name = nameSanitizer.Replace(name, "");
if (!string.IsNullOrWhiteSpace(name))
{
multiplexer.LogLocked(log, "Setting client name: {0}", name);
msg = Message.Create(-1, CommandFlags.FireAndForget, RedisCommand.CLIENT, RedisLiterals.SETNAME, (RedisValue)name);
msg.SetInternalCall();
WriteDirectOrQueueFireAndForget(connection, msg, ResultProcessor.DemandOK);
}
}
}
var connType = connection.Bridge.ConnectionType;
if (connType == ConnectionType.Interactive)
{
multiplexer.LogLocked(log, "Auto-configure...");
AutoConfigure(connection);
}
multiplexer.LogLocked(log, "Sending critical tracer: {0}", connection.Bridge);
var tracer = GetTracerMessage(true);
tracer = LoggingMessage.Create(log, tracer);
WriteDirectOrQueueFireAndForget(connection, tracer, ResultProcessor.EstablishConnection);
// note: this **must** be the last thing on the subscription handshake, because after this
// we will be in subscriber mode: regular commands cannot be sent
if (connType == ConnectionType.Subscription)
{
var configChannel = multiplexer.ConfigurationChangedChannel;
if(configChannel != null)
{
msg = Message.Create(-1, CommandFlags.FireAndForget, RedisCommand.SUBSCRIBE, (RedisChannel)configChannel);
WriteDirectOrQueueFireAndForget(connection, msg, ResultProcessor.TrackSubscriptions);
}
}
multiplexer.LogLocked(log, "Flushing outbound buffer");
connection.Flush();
}
private void SetConfig<T>(ref T field, T value, [CallerMemberName] string caller = null)
{
if(!EqualityComparer<T>.Default.Equals(field, value))
{
multiplexer.Trace(caller + " changed from " + field + " to " + value, "Configuration");
field = value;
multiplexer.ReconfigureIfNeeded(endpoint, false, caller);
}
}
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
namespace StackExchange.Redis
{
/// <summary>
/// Describes a sorted-set element with the corresponding value
/// </summary>
public struct SortedSetEntry : IEquatable<SortedSetEntry>, IComparable, IComparable<SortedSetEntry>
{
internal readonly RedisValue element;
internal readonly double score;
/// <summary>
/// Initializes a SortedSetEntry value
/// </summary>
public SortedSetEntry(RedisValue element, double score)
{
this.element = element;
this.score = score;
}
/// <summary>
/// The unique element stored in the sorted set
/// </summary>
public RedisValue Element { get { return element; } }
/// <summary>
/// The score against the element
/// </summary>
public double Score { get { return score; } }
/// <summary>
/// The score against the element
/// </summary>
#if !DNXCORE50
[Browsable(false)]
#endif
[EditorBrowsable(EditorBrowsableState.Never), Obsolete("Please use Score", false)]
public double Value { get { return score; } }
/// <summary>
/// The unique element stored in the sorted set
/// </summary>
#if !DNXCORE50
[Browsable(false)]
#endif
[EditorBrowsable(EditorBrowsableState.Never), Obsolete("Please use Element", false)]
public RedisValue Key { get { return element; } }
/// <summary>
/// Converts to a key/value pair
/// </summary>
public static implicit operator KeyValuePair<RedisValue,double>(SortedSetEntry value)
{
return new KeyValuePair<RedisValue, double>(value.element, value.score);
}
/// <summary>
/// Converts from a key/value pair
/// </summary>
public static implicit operator SortedSetEntry(KeyValuePair<RedisValue, double> value)
{
return new SortedSetEntry(value.Key, value.Value);
}
/// <summary>
/// See Object.ToString()
/// </summary>
public override string ToString()
{
return element + ": " + score;
}
/// <summary>
/// See Object.GetHashCode()
/// </summary>
public override int GetHashCode()
{
return element.GetHashCode() ^ score.GetHashCode();
}
/// <summary>
/// Compares two values for equality
/// </summary>
public override bool Equals(object obj)
{
return obj is SortedSetEntry && Equals((SortedSetEntry)obj);
}
/// <summary>
/// Compares two values for equality
/// </summary>
public bool Equals(SortedSetEntry value)
{
return this.score == value.score && this.element == value.element;
}
/// <summary>
/// Compares two values by score
/// </summary>
public int CompareTo(SortedSetEntry value)
{
return this.score.CompareTo(value.score);
}
/// <summary>
/// Compares two values by score
/// </summary>
public int CompareTo(object value)
{
return value is SortedSetEntry ? CompareTo((SortedSetEntry)value) : -1;
}
/// <summary>
/// Compares two values for equality
/// </summary>
public static bool operator ==(SortedSetEntry x, SortedSetEntry y)
{
return x.score == y.score && x.element == y.element;
}
/// <summary>
/// Compares two values for non-equality
/// </summary>
public static bool operator !=(SortedSetEntry x, SortedSetEntry y)
{
return x.score != y.score || x.element != y.element;
}
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
namespace StackExchange.Redis
{
/// <summary>
/// Describes a sorted-set element with the corresponding value
/// </summary>
public struct SortedSetEntry : IEquatable<SortedSetEntry>, IComparable, IComparable<SortedSetEntry>
{
internal readonly RedisValue element;
internal readonly double score;
/// <summary>
/// Initializes a SortedSetEntry value
/// </summary>
public SortedSetEntry(RedisValue element, double score)
{
this.element = element;
this.score = score;
}
/// <summary>
/// The unique element stored in the sorted set
/// </summary>
public RedisValue Element { get { return element; } }
/// <summary>
/// The score against the element
/// </summary>
public double Score { get { return score; } }
/// <summary>
/// The score against the element
/// </summary>
#if !DNXCORE50
[Browsable(false)]
#endif
[EditorBrowsable(EditorBrowsableState.Never), Obsolete("Please use Score", false)]
public double Value { get { return score; } }
/// <summary>
/// The unique element stored in the sorted set
/// </summary>
#if !DNXCORE50
[Browsable(false)]
#endif
[EditorBrowsable(EditorBrowsableState.Never), Obsolete("Please use Element", false)]
public RedisValue Key { get { return element; } }
/// <summary>
/// Converts to a key/value pair
/// </summary>
public static implicit operator KeyValuePair<RedisValue,double>(SortedSetEntry value)
{
return new KeyValuePair<RedisValue, double>(value.element, value.score);
}
/// <summary>
/// Converts from a key/value pair
/// </summary>
public static implicit operator SortedSetEntry(KeyValuePair<RedisValue, double> value)
{
return new SortedSetEntry(value.Key, value.Value);
}
/// <summary>
/// See Object.ToString()
/// </summary>
public override string ToString()
{
return element + ": " + score;
}
/// <summary>
/// See Object.GetHashCode()
/// </summary>
public override int GetHashCode()
{
return element.GetHashCode() ^ score.GetHashCode();
}
/// <summary>
/// Compares two values for equality
/// </summary>
public override bool Equals(object obj)
{
return obj is SortedSetEntry && Equals((SortedSetEntry)obj);
}
/// <summary>
/// Compares two values for equality
/// </summary>
public bool Equals(SortedSetEntry value)
{
return this.score == value.score && this.element == value.element;
}
/// <summary>
/// Compares two values by score
/// </summary>
public int CompareTo(SortedSetEntry value)
{
return this.score.CompareTo(value.score);
}
/// <summary>
/// Compares two values by score
/// </summary>
public int CompareTo(object value)
{
return value is SortedSetEntry ? CompareTo((SortedSetEntry)value) : -1;
}
/// <summary>
/// Compares two values for equality
/// </summary>
public static bool operator ==(SortedSetEntry x, SortedSetEntry y)
{
return x.score == y.score && x.element == y.element;
}
/// <summary>
/// Compares two values for non-equality
/// </summary>
public static bool operator !=(SortedSetEntry x, SortedSetEntry y)
{
return x.score != y.score || x.element != y.element;
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{75CED009-AAC6-4AC1-9C38-A0530619062D}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>StackExchange.Redis</RootNamespace>
<AssemblyName>StackExchange.Redis.StrongName</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin.snk\Debug\</OutputPath>
<DefineConstants>TRACE;DEBUG;NET40 STRONG_NAME FEATURE_SERIALIZATION FEATURE_SOCKET_MODE_POLL</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<UseVSHostingProcess>false</UseVSHostingProcess>
<DocumentationFile>bin.snk\Debug\StackExchange.Redis.StrongName.xml</DocumentationFile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin.snk\Release\</OutputPath>
<DefineConstants>TRACE;NET40 STRONG_NAME FEATURE_SERIALIZATION FEATURE_SOCKET_MODE_POLL</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<UseVSHostingProcess>false</UseVSHostingProcess>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DocumentationFile>bin.snk\Release\StackExchange.Redis.StrongName.xml</DocumentationFile>
</PropertyGroup>
<PropertyGroup>
<SignAssembly>true</SignAssembly>
</PropertyGroup>
<PropertyGroup>
<AssemblyOriginatorKeyFile>StackExchange.Redis.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Mono|AnyCPU'">
<OutputPath>bin\Mono\</OutputPath>
<DefineConstants>TRACE;NET40 STRONG_NAME FEATURE_SERIALIZATION</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DocumentationFile>bin.snk\Release\StackExchange.Redis.StrongName.xml</DocumentationFile>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.Threading.Tasks">
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Threading.Tasks.Extensions">
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Threading.Tasks.Extensions.Desktop">
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.IO">
<HintPath>..\packages\Microsoft.Bcl.1.1.10\lib\net40\System.IO.dll</HintPath>
</Reference>
<Reference Include="System.Net" />
<Reference Include="System.Runtime">
<HintPath>..\packages\Microsoft.Bcl.1.1.10\lib\net40\System.Runtime.dll</HintPath>
</Reference>
<Reference Include="System.Threading.Tasks">
<HintPath>..\packages\Microsoft.Bcl.1.1.10\lib\net40\System.Threading.Tasks.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\StackExchange.Redis\Properties\AssemblyInfo.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\Aggregate.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\Bitwise.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ClientFlags.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ClientInfo.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ClientType.cs">
<Link>ClientType.cs</Link>
</Compile>
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\Compat\ConvertHelper.cs">
<Link>ConvertHelper.cs</Link>
</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\ConnectionMultiplexer.Profiling.cs">
<DependentUpon>ConnectionMultiplexer.cs</DependentUpon>
</Compile>
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ClusterConfiguration.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\CommandFlags.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\CommandMap.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\CommandTrace.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\CompletedDefaultTask.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\CompletionManager.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\Condition.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ConfigurationOptions.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ConnectionCounters.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ConnectionFailedEventArgs.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ConnectionFailureType.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ConnectionMultiplexer.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ConnectionMultiplexer.ReaderWriter.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ConnectionType.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\DebuggingAids.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\EndPointCollection.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\EndPointEventArgs.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ExceptionFactory.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\Exclude.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ExportOptions.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ExtensionMethods.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\Format.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\HashEntry.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\HashSlotMovedEventArgs.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\IBatch.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ICompletable.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\IConnectionMultiplexer.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\IDatabase.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\IDatabaseAsync.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\IMultiMessage.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\IRedis.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\IRedisAsync.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\IServer.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ISubscriber.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ITransaction.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\LoggingTextStream.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\Message.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\MessageCompletable.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\MessageQueue.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\MigrateOptions.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ProfileContextTracker.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ProfileStorage.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\LuaScript.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\Order.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\PhysicalBridge.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\PhysicalConnection.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RawResult.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisBase.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisBatch.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisChannel.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisCommand.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisDatabase.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisErrorEventArgs.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisFeatures.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisKey.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisLiterals.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisResult.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisServer.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisSubscriber.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisTransaction.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisType.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisValue.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ReplicationChangeOptions.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ResultBox.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ResultProcessor.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ResultType.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ScriptParameterMapper.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\SaveType.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ServerCounters.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ServerEndPoint.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ServerSelectionStrategy.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ServerType.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\SetOperation.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ShutdownMode.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\SocketManager.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\SocketManager.NoPoll.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\SocketManager.Poll.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\SortedSetEntry.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\SortType.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\StringSplits.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\TaskSource.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\When.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\KeyspaceIsolation\BatchWrapper.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\KeyspaceIsolation\DatabaseExtension.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\KeyspaceIsolation\DatabaseWrapper.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\KeyspaceIsolation\TransactionWrapper.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\KeyspaceIsolation\WrapperBase.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
<None Include="StackExchange.Redis.snk" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets" Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" />
<Target Name="EnsureBclBuildImported" BeforeTargets="BeforeBuild" Condition="'$(BclBuildImported)' == ''">
<Error Condition="!Exists('..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" Text="This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=317567." HelpKeyword="BCLBUILD2001" />
<Error Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" Text="The build restored NuGet packages. Build the project again to include these packages in the build. For more information, see http://go.microsoft.com/fwlink/?LinkID=317568." HelpKeyword="BCLBUILD2002" />
</Target>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{75CED009-AAC6-4AC1-9C38-A0530619062D}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>StackExchange.Redis</RootNamespace>
<AssemblyName>StackExchange.Redis.StrongName</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin.snk\Debug\</OutputPath>
<DefineConstants>TRACE;DEBUG;NET40 STRONG_NAME FEATURE_SERIALIZATION FEATURE_SOCKET_MODE_POLL</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<UseVSHostingProcess>false</UseVSHostingProcess>
<DocumentationFile>bin.snk\Debug\StackExchange.Redis.StrongName.xml</DocumentationFile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin.snk\Release\</OutputPath>
<DefineConstants>TRACE;NET40 STRONG_NAME FEATURE_SERIALIZATION FEATURE_SOCKET_MODE_POLL</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<UseVSHostingProcess>false</UseVSHostingProcess>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DocumentationFile>bin.snk\Release\StackExchange.Redis.StrongName.xml</DocumentationFile>
</PropertyGroup>
<PropertyGroup>
<SignAssembly>true</SignAssembly>
</PropertyGroup>
<PropertyGroup>
<AssemblyOriginatorKeyFile>StackExchange.Redis.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Mono|AnyCPU'">
<OutputPath>bin\Mono\</OutputPath>
<DefineConstants>TRACE;NET40 STRONG_NAME FEATURE_SERIALIZATION</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DocumentationFile>bin.snk\Release\StackExchange.Redis.StrongName.xml</DocumentationFile>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.Threading.Tasks">
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Threading.Tasks.Extensions">
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Threading.Tasks.Extensions.Desktop">
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.IO">
<HintPath>..\packages\Microsoft.Bcl.1.1.10\lib\net40\System.IO.dll</HintPath>
</Reference>
<Reference Include="System.Net" />
<Reference Include="System.Runtime">
<HintPath>..\packages\Microsoft.Bcl.1.1.10\lib\net40\System.Runtime.dll</HintPath>
</Reference>
<Reference Include="System.Threading.Tasks">
<HintPath>..\packages\Microsoft.Bcl.1.1.10\lib\net40\System.Threading.Tasks.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\StackExchange.Redis\Properties\AssemblyInfo.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\Aggregate.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\Bitwise.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ClientFlags.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ClientInfo.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ClientType.cs">
<Link>ClientType.cs</Link>
</Compile>
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\Compat\ConvertHelper.cs">
<Link>ConvertHelper.cs</Link>
</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\ConnectionMultiplexer.Profiling.cs">
<DependentUpon>ConnectionMultiplexer.cs</DependentUpon>
</Compile>
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ClusterConfiguration.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\CommandFlags.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\CommandMap.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\CommandTrace.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\CompletedDefaultTask.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\CompletionManager.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\Condition.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ConfigurationOptions.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ConnectionCounters.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ConnectionFailedEventArgs.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ConnectionFailureType.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ConnectionMultiplexer.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ConnectionMultiplexer.ReaderWriter.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ConnectionType.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\DebuggingAids.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\EndPointCollection.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\EndPointEventArgs.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ExceptionFactory.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\Exclude.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ExportOptions.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ExtensionMethods.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\Format.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\HashEntry.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\HashSlotMovedEventArgs.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\IBatch.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ICompletable.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\IConnectionMultiplexer.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\IDatabase.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\IDatabaseAsync.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\IMultiMessage.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\IRedis.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\IRedisAsync.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\IServer.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ISubscriber.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ITransaction.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\LoggingTextStream.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\Message.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\MessageCompletable.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\MessageQueue.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\MigrateOptions.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ProfileContextTracker.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ProfileStorage.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\LuaScript.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\Order.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\PhysicalBridge.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\PhysicalConnection.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RawResult.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisBase.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisBatch.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisChannel.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisCommand.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisDatabase.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisErrorEventArgs.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisFeatures.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisKey.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisLiterals.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisResult.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisServer.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisSubscriber.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisTransaction.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisType.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisValue.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ReplicationChangeOptions.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ResultBox.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ResultProcessor.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ResultType.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ScriptParameterMapper.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\SaveType.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ServerCounters.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ServerEndPoint.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ServerSelectionStrategy.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ServerType.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\SetOperation.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ShutdownMode.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\SocketManager.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\SocketManager.NoPoll.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\SocketManager.Poll.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\SortedSetEntry.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\SortType.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\StringSplits.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\TaskSource.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\When.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\KeyspaceIsolation\BatchWrapper.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\KeyspaceIsolation\DatabaseExtension.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\KeyspaceIsolation\DatabaseWrapper.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\KeyspaceIsolation\TransactionWrapper.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\KeyspaceIsolation\WrapperBase.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
<None Include="StackExchange.Redis.snk" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets" Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" />
<Target Name="EnsureBclBuildImported" BeforeTargets="BeforeBuild" Condition="'$(BclBuildImported)' == ''">
<Error Condition="!Exists('..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" Text="This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=317567." HelpKeyword="BCLBUILD2001" />
<Error Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" Text="The build restored NuGet packages. Build the project again to include these packages in the build. For more information, see http://go.microsoft.com/fwlink/?LinkID=317568." HelpKeyword="BCLBUILD2002" />
</Target>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{36CAC6B6-2B88-447F-AA35-D4DAA5E4F2C7}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>StackExchange.Redis</RootNamespace>
<AssemblyName>StackExchange.Redis</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>TRACE;DEBUG;NET40 FEATURE_SERIALIZATION FEATURE_SOCKET_MODE_POLL</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<UseVSHostingProcess>false</UseVSHostingProcess>
<DocumentationFile>bin\Debug\StackExchange.Redis.XML</DocumentationFile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE;NET40 FEATURE_SERIALIZATION FEATURE_SOCKET_MODE_POLL</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<UseVSHostingProcess>false</UseVSHostingProcess>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DocumentationFile>bin\Release\StackExchange.Redis.xml</DocumentationFile>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Mono|AnyCPU'">
<OutputPath>bin\Mono\</OutputPath>
<DefineConstants>TRACE;NET40 FEATURE_SERIALIZATION</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DocumentationFile>bin\Release\StackExchange.Redis.xml</DocumentationFile>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.Threading.Tasks">
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Threading.Tasks.Extensions">
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Threading.Tasks.Extensions.Desktop">
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.IO, Version=2.6.10.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Bcl.1.1.10\lib\net40\System.IO.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Net" />
<Reference Include="System.Runtime, Version=2.6.10.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Bcl.1.1.10\lib\net40\System.Runtime.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Threading.Tasks, Version=2.6.10.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Bcl.1.1.10\lib\net40\System.Threading.Tasks.dll</HintPath>
<Private>True</Private>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\StackExchange.Redis\Properties\AssemblyInfo.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\Aggregate.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\Bitwise.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ClientFlags.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ClientInfo.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ClientType.cs">
<Link>ClientType.cs</Link>
</Compile>
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\Compat\ConvertHelper.cs">
<Link>ConvertHelper.cs</Link>
</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\ConnectionMultiplexer.Profiling.cs">
<DependentUpon>ConnectionMultiplexer.cs</DependentUpon>
</Compile>
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ClusterConfiguration.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\CommandFlags.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\CommandMap.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\CommandTrace.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\CompletedDefaultTask.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\CompletionManager.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\Condition.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ConfigurationOptions.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ConnectionCounters.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ConnectionFailedEventArgs.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ConnectionFailureType.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ConnectionMultiplexer.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ConnectionMultiplexer.ReaderWriter.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ConnectionType.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\DebuggingAids.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\EndPointCollection.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\EndPointEventArgs.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ExceptionFactory.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\Exclude.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ExportOptions.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ExtensionMethods.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\Format.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\HashEntry.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\HashSlotMovedEventArgs.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\IBatch.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ICompletable.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\IConnectionMultiplexer.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\IDatabase.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\IDatabaseAsync.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\IMultiMessage.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\IRedis.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\IRedisAsync.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\IServer.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ISubscriber.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ITransaction.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\LoggingTextStream.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\Message.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\MessageCompletable.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\MessageQueue.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\MigrateOptions.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ProfileContextTracker.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ProfileStorage.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\LuaScript.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\Order.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\PhysicalBridge.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\PhysicalConnection.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RawResult.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisBase.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisBatch.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisChannel.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisCommand.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisDatabase.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisErrorEventArgs.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisFeatures.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisKey.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisLiterals.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisResult.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisServer.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisSubscriber.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisTransaction.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisType.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisValue.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ReplicationChangeOptions.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ResultBox.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ResultProcessor.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ResultType.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ScriptParameterMapper.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\SaveType.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ServerCounters.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ServerEndPoint.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ServerSelectionStrategy.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ServerType.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\SetOperation.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ShutdownMode.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\SocketManager.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\SocketManager.NoPoll.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\SocketManager.Poll.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\SortedSetEntry.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\SortType.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\StringSplits.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\TaskSource.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\When.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\KeyspaceIsolation\BatchWrapper.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\KeyspaceIsolation\DatabaseExtension.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\KeyspaceIsolation\DatabaseWrapper.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\KeyspaceIsolation\TransactionWrapper.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\KeyspaceIsolation\WrapperBase.cs" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets" Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" />
<Target Name="EnsureBclBuildImported" BeforeTargets="BeforeBuild" Condition="'$(BclBuildImported)' == ''">
<Error Condition="!Exists('..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" Text="This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=317567." HelpKeyword="BCLBUILD2001" />
<Error Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" Text="The build restored NuGet packages. Build the project again to include these packages in the build. For more information, see http://go.microsoft.com/fwlink/?LinkID=317568." HelpKeyword="BCLBUILD2002" />
</Target>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{36CAC6B6-2B88-447F-AA35-D4DAA5E4F2C7}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>StackExchange.Redis</RootNamespace>
<AssemblyName>StackExchange.Redis</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>TRACE;DEBUG;NET40 FEATURE_SERIALIZATION FEATURE_SOCKET_MODE_POLL</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<UseVSHostingProcess>false</UseVSHostingProcess>
<DocumentationFile>bin\Debug\StackExchange.Redis.XML</DocumentationFile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE;NET40 FEATURE_SERIALIZATION FEATURE_SOCKET_MODE_POLL</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<UseVSHostingProcess>false</UseVSHostingProcess>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DocumentationFile>bin\Release\StackExchange.Redis.xml</DocumentationFile>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Mono|AnyCPU'">
<OutputPath>bin\Mono\</OutputPath>
<DefineConstants>TRACE;NET40 FEATURE_SERIALIZATION</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DocumentationFile>bin\Release\StackExchange.Redis.xml</DocumentationFile>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.Threading.Tasks">
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Threading.Tasks.Extensions">
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Threading.Tasks.Extensions.Desktop">
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.IO, Version=2.6.10.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Bcl.1.1.10\lib\net40\System.IO.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Net" />
<Reference Include="System.Runtime, Version=2.6.10.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Bcl.1.1.10\lib\net40\System.Runtime.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Threading.Tasks, Version=2.6.10.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Bcl.1.1.10\lib\net40\System.Threading.Tasks.dll</HintPath>
<Private>True</Private>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\StackExchange.Redis\Properties\AssemblyInfo.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\Aggregate.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\Bitwise.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ClientFlags.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ClientInfo.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ClientType.cs">
<Link>ClientType.cs</Link>
</Compile>
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\Compat\ConvertHelper.cs">
<Link>ConvertHelper.cs</Link>
</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\ConnectionMultiplexer.Profiling.cs">
<DependentUpon>ConnectionMultiplexer.cs</DependentUpon>
</Compile>
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ClusterConfiguration.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\CommandFlags.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\CommandMap.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\CommandTrace.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\CompletedDefaultTask.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\CompletionManager.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\Condition.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ConfigurationOptions.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ConnectionCounters.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ConnectionFailedEventArgs.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ConnectionFailureType.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ConnectionMultiplexer.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ConnectionMultiplexer.ReaderWriter.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ConnectionType.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\DebuggingAids.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\EndPointCollection.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\EndPointEventArgs.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ExceptionFactory.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\Exclude.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ExportOptions.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ExtensionMethods.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\Format.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\HashEntry.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\HashSlotMovedEventArgs.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\IBatch.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ICompletable.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\IConnectionMultiplexer.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\IDatabase.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\IDatabaseAsync.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\IMultiMessage.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\IRedis.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\IRedisAsync.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\IServer.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ISubscriber.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ITransaction.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\LoggingTextStream.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\Message.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\MessageCompletable.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\MessageQueue.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\MigrateOptions.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ProfileContextTracker.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ProfileStorage.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\LuaScript.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\Order.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\PhysicalBridge.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\PhysicalConnection.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RawResult.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisBase.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisBatch.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisChannel.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisCommand.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisDatabase.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisErrorEventArgs.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisFeatures.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisKey.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisLiterals.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisResult.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisServer.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisSubscriber.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisTransaction.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisType.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\RedisValue.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ReplicationChangeOptions.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ResultBox.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ResultProcessor.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ResultType.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ScriptParameterMapper.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\SaveType.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ServerCounters.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ServerEndPoint.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ServerSelectionStrategy.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ServerType.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\SetOperation.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\ShutdownMode.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\SocketManager.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\SocketManager.NoPoll.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\SocketManager.Poll.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\SortedSetEntry.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\SortType.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\StringSplits.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\TaskSource.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\When.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\KeyspaceIsolation\BatchWrapper.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\KeyspaceIsolation\DatabaseExtension.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\KeyspaceIsolation\DatabaseWrapper.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\KeyspaceIsolation\TransactionWrapper.cs" />
<Compile Include="..\StackExchange.Redis\StackExchange\Redis\KeyspaceIsolation\WrapperBase.cs" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets" Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" />
<Target Name="EnsureBclBuildImported" BeforeTargets="BeforeBuild" Condition="'$(BclBuildImported)' == ''">
<Error Condition="!Exists('..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" Text="This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=317567." HelpKeyword="BCLBUILD2001" />
<Error Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" Text="The build restored NuGet packages. Build the project again to include these packages in the build. For more information, see http://go.microsoft.com/fwlink/?LinkID=317568." HelpKeyword="BCLBUILD2002" />
</Target>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>
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